山东大学软件工程项目实训(2021-4)
发现用户安全问题,需要token工具类,进行token代码开发和拦截器过滤器开发
一、本阶段工作进展
1.学习jwt构建token工具类
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。
- 用户使用账号和面发出post请求;
- 服务器使用私钥创建一个jwt;
- 服务器返回这个jwt给浏览器;
- 浏览器将该jwt串在请求头中像服务器发送请求;
- 服务器验证该jwt;
- 返回响应的资源给浏览器。
2.实现create/check/refresh token相关函数
2.1 目标
该工具类主要为实现User类的信息加密存储,传输。
对登录的用户进行验证,生成带有id信息的唯一加密的token,用于前后端传输。
public class User {
private Long id; //用户id
private String username; //用户名
private String password; //用户密码
private String name; //用户姓名
private Integer post; //用户职务
}
2.2 测试
测试程序(忽略优化输出格式的代码)
/** test tokenUtil **/
/** create user **/
User user = new User();
user.setId(123l);
user.setName("testToken");
user.setUsername("taoTest");
user.setPassword("123testToken");
user.setPost(2);
System.out.println("|--usr info:\t\t\t"+user.getId());
/** test createToken() **/
String token = TokenUtil.createToken(user);
System.out.println("|--token: \t\t\t"+token);
/** test decodeToken() **/
long res = TokenUtil.decodeToken(token);
System.out.println("|--res from decodeToken():\t\t\t"+res);
/** test refreshToken() **/
String newToken1 = TokenUtil.refreshToken(token);
System.out.println("|--newToken1: \t\t\t"+newToken1);
TokenUtil.tokenExpireTime = 1;
String token2 = TokenUtil.createToken(user);
System.out.println("|--wait...");
TimeUnit.MINUTES.sleep(1);//分
String newToken2 = TokenUtil.refreshToken(token2);
System.out.println("|--newToken2: \t\t\t"+newToken2);
测试结果(成功实现相关功能)
二、程序具体实现与解读
1. 相关设置
private static Integer tokenExpireTime = 10; //token过期时间,单位分钟
private static String secretKey = "XXXXXXXXXXXX"; // 固定的服务器私钥
2. 生成token
根据user的id和服务器的密钥生成唯一加密的token。
输入 | 输出 |
---|---|
User类对象 | String类型token |
public static String createToken(User user) {
// id + JWT私钥加密
String secret = secretKey + user.getId();
// 过期时间,单位:毫秒
long expireTime = System.currentTimeMillis() + tokenExpireTime*60*1000L;
// 将 userId + currentTime 保存到 token 里面; 以 secret 作为 token 的密钥
String token= JWT.create().withAudience(user.getId() +";;"+ expireTime)
.sign(Algorithm.HMAC256(secret));
return token;
}
2. 解读token
根据token获取其中的userId。
输入 | 输出 |
---|---|
String类型token | long类型userId |
public static long decodeToken(String token) {
// 判null
if (token == null) {
throw new RuntimeException("Error: token is null in decodeToken ");
}
// 获取 token 中的 user id
String content;
try {
content = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("401 (jwt decode error)");
}
long userId = Long.parseLong(content.split(";;")[0]);
return userId;
}
3. 刷新token
根据token获取其中的过期时间判断是否进行刷新操作。
输入 | 输出1 | 输出2 |
---|---|---|
String类型token | 原token(未过期) | 新token(过期) |
public static String refreshToken(String token) {
//根据有效期检查是否需要更新Token
if (token != null){
String content;
try {
content = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("401 (jwt decode error)");
}
long expireTime = Long.parseLong(content.split(";;")[1]);
long currentTime = System.currentTimeMillis();
long userIdToken = Long.parseLong(content.split(";;")[0]);
if (currentTime > expireTime){
// 已失效
String secret = secretKey + userIdToken;
long newExpireTime = System.currentTimeMillis() + tokenExpireTime*60*1000L;
String newToken= JWT.create().withAudience(userIdToken +";;"+ expireTime)
.sign(Algorithm.HMAC256(secret));
return newToken;
}
}else {
throw new RuntimeException("Error: token is null in refreshToken ");
}
return token;
}
暂时未用的验证 token
// public static Boolean checkToken(String token) {
// // 判null
// if (token == null) {
// throw new RuntimeException("Error: token is null in checkToken ");
// }
// // 获取 token 中的 user id
// String content;
// try {
// content = JWT.decode(token).getAudience().get(0);
//
// } catch (JWTDecodeException j) {
// throw new RuntimeException("401 (jwt decode error)");
// }
// long userId = Long.parseLong(content.split(";;")[0]);
// User user = userMapper.selectOne(userId);
// if (user == null) {
// throw new RuntimeException("用户不存在,请重新登录");
// }
// // 验证 token 如果验证失败应该返回FALSE???
// JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
// try {
// jwtVerifier.verify(token);
// } catch (JWTVerificationException e) {
// throw new RuntimeException("401 (jwt verify error)");
// }
// return true;
// }
三、下一阶段工作目标
实现拦截器,联系前端进行调试