import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* @ProjectName: LieIdle
* @Package: com.utils
* @Author: huat
* @Date: 2020/4/8 16:57
* @Version: 1.0
*/
@Slf4j
public class JsonUtil {
public static final ObjectMapper objectMapper=new ObjectMapper();
/**
* 将对象转为json
* @param object 对象
* @return json
*/
public static String ObjectToString(Object object) {
if(null==object){
return null;
}
if(object.getClass()==String.class){
return (String)object;
}
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
log.info(object+"序列化出错"+e.getMessage());
e.printStackTrace();
return null;
}
}
/**
* 将json转换成对象
* @param json json字符串
* @param tClass 类
* @param <T> 泛型
* @return 返回对象
*/
public static <T> T toBean(String json,Class<T> tClass){
try {
return objectMapper.readValue(json,tClass);
} catch (IOException e) {
log.info(json+"转对象失败"+e.getMessage());
e.printStackTrace();
return null;
}
}
}
package cn.bdqn.token;
import cn.bdqn.entity.Payload;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
import javax.servlet.http.HttpServletRequest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
/**
* @ProjectName: LieIdle
* @Package: com.utils
* @Author: huat
* @Date: 2020/4/8 16:22
* @Version: 1.0
*/
public class JwtUtil {
private final static String JWT_PAYLOAD_USER_KEY = "user";
/**
* 私钥加密token
*
* @param userInfo 载荷中的数据
* @param privateKey 私钥
* @param expire 过期时间 单位分钟
* @return
*/
public static String generateTokenExpireInMinutes(Object userInfo, PrivateKey privateKey, int expire) {
return Jwts.builder()
.claim(JWT_PAYLOAD_USER_KEY, JsonUtil.ObjectToString(userInfo))
.setId(createJTI())
.setExpiration(DateTime.now().plusMinutes(expire).toDate())
.signWith(privateKey, SignatureAlgorithm.RS256)
.compact();
}
/**
* 私钥加密token
*
* @param userInfo 载荷中的数据
* @param privateKey 私钥
* @param expire 过期时间 单位秒
* @return
*/
public static String generateTokenExpireInSeconds(Object userInfo, PrivateKey privateKey, int expire) {
return Jwts.builder()
.claim(JWT_PAYLOAD_USER_KEY, JsonUtil.ObjectToString(userInfo))
.setId(createJTI())
.setExpiration(DateTime.now().plusSeconds(expire).toDate())
.signWith(privateKey, SignatureAlgorithm.RS256)
.compact();
}
private static String createJTI() {
return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
}
/**
* 公钥解析token
* @param token 用户请求的令牌
* @param publicKey 公钥
* @return
*/
private static Jws<Claims> parserToken(String token, PublicKey publicKey){
return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
}
/**
* 获取token中的载荷信息
* @param token 用户请求的令牌
* @param publicKey 公钥
* @param userType 用户类型
* @param <T>
* @return 用户信息
*/
public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey, Class<T> userType) {
Jws<Claims> claimsJws = parserToken(token, publicKey);
Claims body = claimsJws.getBody();
Payload<T> payload = new Payload<T>();
payload.setId(body.getId());
payload.setUserInfo(JsonUtil.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(),userType));
payload.setExpiration(body.getExpiration());
return payload;
}
/**
* 获取token中的载荷信息
* @param token 用户请求的令牌
* @param publicKey 公钥
* @param <T>
* @return 用户信息
*/
public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey) {
Jws<Claims> claimsJws = parserToken(token, publicKey);
Claims body = claimsJws.getBody();
Payload<T> payload = new Payload<T>();
payload.setId(body.getId());
payload.setExpiration(body.getExpiration());
return payload;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
/**
* @ProjectName: LieIdle
* @Package: com.utils
* @Author: huat
* @Date: 2020/4/8 17:09
* @Version: 1.0
*/
@Configuration
@ConfigurationProperties("rsa.key")//从配置文件中获取头信息是rsa.key的配置
public class RsaKeyProperties {
private String publicKeyFile;
private String privateKeyFile;
private PublicKey publicKey;
private PrivateKey privateKey;
@PostConstruct//在初始化完成之后执行此方法
public void createRsaKey() throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
publicKey=RsaUtil.getPublicKey(publicKeyFile);
privateKey=RsaUtil.getPrivateKey(privateKeyFile);
}
public String getPublicKeyFile() {
return publicKeyFile;
}
public void setPublicKeyFile(String publicKeyFile) {
this.publicKeyFile = publicKeyFile;
}
public String getPrivateKeyFile() {
return privateKeyFile;
}
public PublicKey getPublicKey() {
return publicKey;
}
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
}
public PrivateKey getPrivateKey() {
return privateKey;
}
public void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
}
public void setPrivateKeyFile(String privateKeyFile) {
this.privateKeyFile = privateKeyFile;
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* @ProjectName: LieIdle
* @Package: com.utils
* @Author: huat
* @Date: 2020/4/8 17:09
* @Version: 1.0
*/
public class RsaUtil {
private final static int DEFAULT_KEY_SIZE=2048;
/**
* 根据密文,生成rea公钥和私钥,并写入指定文件
* @param publicKeyFileName 公钥文件路径
* @param privateKeyFileName 私钥文件路径
* @param secret 盐
* @param keySize 大小
*/
public static void generateKey(String publicKeyFileName,String privateKeyFileName,String secret, int keySize) throws NoSuchAlgorithmException, IOException {
KeyPairGenerator keyPairGenerator= KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom=new SecureRandom(secret.getBytes());
keyPairGenerator.initialize(Math.max(keySize,DEFAULT_KEY_SIZE),secureRandom);
KeyPair keyPair=keyPairGenerator.genKeyPair();
//获取公钥并写出
byte[] publicKeyByte=keyPair.getPublic().getEncoded();
publicKeyByte= Base64.getEncoder().encode(publicKeyByte);
writeFile(publicKeyFileName,publicKeyByte);
//获取公钥并写入
byte[] privateKeyByte=keyPair.getPrivate().getEncoded();
privateKeyByte= Base64.getEncoder().encode(privateKeyByte);
writeFile(privateKeyFileName,privateKeyByte);
}
/**
* 获取秘钥
* @param bytes 秘钥的字节形式
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
bytes=Base64.getDecoder().decode(bytes);
PKCS8EncodedKeySpec spec=new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
}
/**
* 获取公钥
* @param bytes 公钥的字节形式
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private static PublicKey getPublicKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
bytes=Base64.getDecoder().decode(bytes);
X509EncodedKeySpec spec=new X509EncodedKeySpec(bytes);
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
}
/**
* 从文件中读取公钥
* @param fileName 公钥保存路径 相对于classpath
* @return 公钥对象
* @throws InvalidKeySpecException
* @throws NoSuchAlgorithmException
*/
public static PublicKey getPublicKey(String fileName) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
byte[] bytes=readFile(fileName);
return getPublicKey(bytes);
}
/**
* 从文件中读取公钥
* @param fileName 公钥保存路径 相对于classpath
* @return 私钥对象
* @throws InvalidKeySpecException
* @throws NoSuchAlgorithmException
*/
public static PrivateKey getPrivateKey(String fileName) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
byte[] bytes=readFile(fileName);
return getPrivateKey(bytes);
}
private static byte[] readFile(String fileName) throws IOException {
return Files.readAllBytes(new File(fileName).toPath());
}
private static void writeFile(String fileName,byte[] bytes) throws IOException {
File file=new File(fileName);
if(!file.exists()){
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream( fileName);
fos.write(bytes);
fos.close();
}
public static void main(String[] args) {
try {
generateKey("E:\\桌面\\public.pub","E:\\桌面\\private","jinzhending,@,",2048);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import cn.bdqn.entity.User;
import cn.bdqn.service.UserService;
import cn.bdqn.token.JwtUtil;
import cn.bdqn.token.RsaKeyProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* @ProjectName: Student
* @Package: com.controller
* @Author: huat
* @Date: 2020/5/11 14:54
* @Version: 1.0
*/
@RestController
public class LoginController {
@Autowired
UserService userService;
@Autowired
RsaKeyProperties rsaKeyProperties;
/**
* 登陆
* @param username 账号
* @param password 密码
* @return
*/
@PostMapping("login")
public Map<String,Object> login(String username, String password, HttpServletResponse response){
Map<String,Object> map=new HashMap<String,Object>();
User user= userService.getUser(username, password);
if(null!=user){
map.put("code",200);
map.put("msg","登陆成功");
map.put("data","");
String token= JwtUtil.generateTokenExpireInMinutes(user,rsaKeyProperties.getPrivateKey(),24*60);
//必须有这句话否则前台获取不到token
response.setHeader("Access-Control-Expose-Headers", "Authorization");
response.setHeader("Authorization","bearer "+token);
}else{
map.put("code",500);
map.put("msg","账号密码错误");
map.put("data","");
}
return map;
}
}
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* @ProjectName: Student
* @Package: com.filter
* @Author: huat
* @Date: 2020/5/11 15:31
* @Version: 1.0
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
/**
* 预处理回调方法,实现处理器的预处理
* 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或处理器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String header = request.getHeader("Authorization");
if(null==header){
Map<String,Object> map=new HashMap<String,Object>();
map.put("code",403);
map.put("data","");
map.put("msg","请重新登陆");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.print(map);
writer.flush();
writer.close();
return false;
}
return true;
}
/**
* 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前
* 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
/**
* 整个请求处理完毕回调方法,即在视图渲染完毕时回调,
* 如性能监控中我们可以在此记录结束时间并输出消耗时间,
* 还可以进行一些资源清理,类似于try-catch-finally中的finally,
* 但仅调用处理器执行链中
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
import cn.bdqn.utils.StaticUrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @ProjectName: Document
* @Package: com.util
* @Author: huat
* @Date: 2019/7/26 10:18
* @Version: 1.0
*/
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
@Autowired
LoginInterceptor loginInterceptor;
// 这个方法是用来配置静态资源的,比如html,js,css,等等
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns("/**") 表示拦截所有的请求,
//excludePathPatterns("/login", "/register"); 表示除了登陆与注册之外,因为登陆注册不需要登陆也可以访问
registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
//super.addInterceptors(registry); //较新Spring Boot的版本中这里可以直接去掉,否则会报错
}
}