<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>1.9.3version>
dependency>
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.0version>
dependency>
<dependency>
<groupId>joda-timegroupId>
<artifactId>joda-timeartifactId>
<version>2.9.7version>
dependency>
public class JwtUtils {
/**
* 私钥加密token
* @param data 需要加密的数据(载荷内容)
* @param expireMinutes 过期时间,单位:分钟
* @param privateKey 私钥
* @return
*/
public static String generateToken(Object data, int expireMinutes, PrivateKey privateKey) throws Exception {
//1 获得jwt构建对象
JwtBuilder jwtBuilder = Jwts.builder();
//2 设置数据
if( data == null ) {
throw new RuntimeException("数据不能为空");
}
BeanInfo beanInfo = Introspector.getBeanInfo(data.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 获得属性名
String name = propertyDescriptor.getName();
// 获得属性值
Object value = propertyDescriptor.getReadMethod().invoke(data);
if(value != null) {
jwtBuilder.claim(name,value);
}
}
//3 设置过期时间
jwtBuilder.setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate());
//4 设置加密
jwtBuilder.signWith(SignatureAlgorithm.RS256, privateKey);
//5 构建
return jwtBuilder.compact();
}
/**
* 通过公钥解析token
* @param token 需要解析的数据
* @param publicKey 公钥
* @param beanClass 封装的JavaBean
* @return
* @throws Exception
*/
public static <T> T getObjectFromToken(String token, PublicKey publicKey,Class<T> beanClass) throws Exception {
//1 获得解析后内容
Claims body = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
//2 将内容封装到对象JavaBean
T bean = beanClass.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 获得属性名
String name = propertyDescriptor.getName();
// 通过属性名,获得对应解析的数据
Object value = body.get(name);
if(value != null) {
// 将获得的数据封装到对应的JavaBean中
BeanUtils.setProperty(bean,name,value);
}
}
return bean;
}
}
public class RasUtils {
/**
* 从文件中读取公钥
*
* @param filename 公钥保存路径,相对于classpath
* @return 公钥对象
* @throws Exception
*/
public static PublicKey getPublicKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPublicKey(bytes);
}
/**
* 从文件中读取密钥
*
* @param filename 私钥保存路径,相对于classpath
* @return 私钥对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPrivateKey(bytes);
}
/**
* 获取公钥
*
* @param bytes 公钥的字节形式
* @return
* @throws Exception
*/
public static PublicKey getPublicKey(byte[] bytes) throws Exception {
X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
/**
* 获取密钥
*
* @param bytes 私钥的字节形式
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKey(byte[] bytes) throws Exception {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}
/**
* 根据密文,生存rsa公钥和私钥,并写入指定文件
*
* @param publicKeyFilename 公钥文件路径
* @param privateKeyFilename 私钥文件路径
* @param secret 生成密钥的密文
* @throws Exception
*/
public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(secret.getBytes());
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// 获取公钥并写出
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
writeFile(publicKeyFilename, publicKeyBytes);
// 获取私钥并写出
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
writeFile(privateKeyFilename, privateKeyBytes);
}
private static byte[] readFile(String fileName) throws Exception {
return Files.readAllBytes(new File(fileName).toPath());
}
private static void writeFile(String destPath, byte[] bytes) throws IOException {
File dest = new File(destPath);
//创建父文件夹
if(!dest.getParentFile().exists()){
dest.getParentFile().mkdirs();
}
//创建需要的文件
if (!dest.exists()) {
dest.createNewFile();
}
Files.write(dest.toPath(), bytes);
}
}
public class TestJwt {
private static final String pubKeyPath = "D:\\temp\\password.pub";
private static final String priKeyPath = "D:\\temp\\password.pri";
@Test
public void testDemo01() throws Exception {
//生成公钥和私钥
RasUtils.generateKey(pubKeyPath,priKeyPath,"123");
}
@Test
public void testGetRas() throws Exception {
//获得公钥和私钥
PublicKey publicKey = RasUtils.getPublicKey(pubKeyPath);
PrivateKey privateKey = RasUtils.getPrivateKey(priKeyPath);
System.out.println(publicKey);
System.out.println(privateKey);
}
}
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
//获得工具类(请求上下文对象)
RequestContext requestContext = RequestContext.getCurrentContext();
//通过工具类获得request对象
HttpServletRequest request = requestContext.getRequest();
//通过请求对象判断是否在登录页面(在登录页面才能点击登录使用登录方法)
//如果不是就放行,进行登录判断,如果是,就不需要登录判断
String requestURI = request.getRequestURI();
//-------------------------------------------------------------------------------------------
//StringBuffer requestURL = request.getRequestURL();注意了,这里非常重要,必须获取的是URI而不是URL,因为我们下面if中
//写的就是URI,如果获取URL下面就需要改成http://localhost:端口号/网关前缀/服务名/一级路径/二级路径.....
//-------------------------------------------------------------------------------------------
// System.out.println(requestURI);
if ("/api/userservice/user/login".equals(requestURI)){
return false;
}
return true;
}
//设置一个存放密码的地址
private static final String pubKeyPath = "D:\\temp\\password.pub";
@Override
public Object run() throws ZuulException {
//获得工具类(请求上下文对象)
RequestContext requestContext = RequestContext.getCurrentContext();
//通过工具类获得request对象
HttpServletRequest request = requestContext.getRequest();
//根据请求头获取token
String token = request.getHeader("authorization");
try {
JwtUtils.getObjectFromToken(token, RasUtils.getPublicKey(pubKeyPath), User.class);
} catch (Exception e) {
e.printStackTrace();
//如果没有找到匹配的数据
//不允许放行
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(403); //这里是你希望在前台响应的错误响应码
}
//放行
return null;
}
}
上面有横杠隔开的地方一定要读!!!
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userServiceImpl;
//设置一个存放密码的地址
private static final String priKeyPath = "D:\\temp\\password.pri";
@PostMapping("/login")
public BaseResult login(@RequestBody User user){
User u = userServiceImpl.login(user);
if (u == null){
return BaseResult.error("用户名或者密码错误");
}else{
//正确登录之后就需要产生token
String token = null;
try {
token = JwtUtils.generateToken(u,30, RasUtils.getPrivateKey(priKeyPath));
} catch (Exception e) {
e.printStackTrace();
}
return BaseResult.ok("登录成功").append("token",token);
}
}
}
async login(){
let {data} = await login(this.user)
if (data.code == 1) {
this.$message.success(data.message)
//获得token,保存到sessionStorage
sessionStorage.setItem('token',data.other.token)
this.$router.push('/home')
}else{
this.$message.error(data.message)
}
}
// 3 配置拦截器
axios.interceptors.request.use(request=>{
let token = sessionStorage.getItem('token')
if(token){
request.headers.authorization = token
}
return request
},error=>{})
axios.interceptors.response.use(response => {
// 放行
return response
}, error => {
// 错误提示
console.info(error)
Message.error(error.message)
return Promise.reject(error)
})
java.nio.file.NoSuchFileException: D:\temp\password.pub
系统没有找到该文件
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: Short read of DER length
我出这个异常的时候因为我的token没有被取出来,token为null