发表于: 2021-04-12 23:24:57
3 1244
今天完成的事情:
图片迁移
修改登录,注册,将密码加密的问题
梳理token的逻辑
完善代码,将Sys.out.println修改成 logger.info
明天计划的事情:
继续了解spring RMI
它可以做什么,解决了什么问题,为什么要用到它,有什么好处
遇到的问题:
1.无法读取Object内容的输入值,系统找不到指定路径
* 图片迁移
* TODO: 代码逻辑:遍历获取阿里云的文件名,将阿里云上的文件转到本地,最后在上传到腾讯云
* FIXME:这里图片迁移的逻辑有问题。
* 1.代码是创建一个父目录,但是没有创建文件。所以它会显示在本地找不到文件。
* 2.获取key的时候,它一开始直接获取image/ 文件夹,并不会获取到详细的文件
* FIXME:目前解决办法:在本地创建文件,获取文件的绝对位置。然后把本地文件当作一个中转地。把获取key(文件名)注释
* FIXME:进一步优化的方法:
* 1.先把阿里云图片全部下载到本地,然后在从本地上传的腾讯云
* 2.想到能不能把redis当作中转站
* 3.师兄提供的办法是,看sdk能不能支持云文件
收获:
JWT 工具类
/**
* 生成jwt的方法
* @param date 签发时间
* @param secrety 私钥
* @param
* @return
*/
public static String getJWT(String id, String userName, Date date, String secrety){
JwtBuilder jwtBuilder= Jwts.builder().setId(id).setIssuer(userName)
.setIssuedAt(date)
.signWith(SignatureAlgorithm.HS256,secrety);
String token = jwtBuilder.compact();
return token;
}
/**
* 解析token
* @param token token
* @param secrety 私钥
* @return
*/
public static Claims parseJWT(String token, String secrety){
Claims claims=Jwts.parser().setSigningKey(secrety).parseClaimsJws(token).getBody();
return claims;
}
拦截器验证token:
//从请求中获取cookie, 判断当前用户是否已经登陆
Cookie cookie = CookieUtil.getCookie(request.getCookies(), "token");
//判断客户端是否有cookie
if (cookie != null) {
//从cookie得到token
String value = URLDecoder.decode(cookie.getValue(), "utf-8");
logger.info("从客户端得到的taken:" + value);
//解密token
Claims token = JWTUtil.parseJWT(value, SECRE);
logger.info("解密的taken:" + token);
if(token!=null){
return true;
}else {
return false;
}
} else {
String headertoken = request.getHeader("token");
logger.info("从客户端得到的taken:" + headertoken);
//解密token
Claims token = JWTUtil.parseJWT(headertoken, SECRE);
if (token != null){
return true;
}else {
logger.info("用户没有登录");
//如果没有检测到登录状态就重定向到登录界面
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
对比网上的逻辑:
public class JwtTokenUtil {
private static Logger log = LoggerFactory.getLogger(JwtTokenUtil.class);
public static final String AUTH_HEADER_KEY = "Authorization";
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 解析jwt
* @param jsonWebToken
* @param base64Security
* @return
*/
public static Claims parseJWT(String jsonWebToken, String base64Security) {
try {
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
.parseClaimsJws(jsonWebToken).getBody();
return claims;
} catch (ExpiredJwtException eje) {
log.error("===== Token过期 =====", eje);
throw new CustomException(ResultCode.PERMISSION_TOKEN_EXPIRED);
} catch (Exception e){
log.error("===== token解析异常 =====", e);
throw new CustomException(ResultCode.PERMISSION_TOKEN_INVALID);
}
}
/**
* 构建jwt
* @param userId
* @param username
* @param role
* @param audience
* @return
*/
public static String createJWT(String userId, String username, String role, Audience audience) {
try {
// 使用HS256加密算法
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//生成签名密钥
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(audience.getBase64Secret());
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//userId是重要信息,进行加密下
String encryId = Base64Util.encode(userId);
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
// 可以将基本不重要的对象信息放到claims
.claim("role", role)
.claim("userId", userId)
.setSubject(username) // 代表这个JWT的主体,即它的所有人
.setIssuer(audience.getClientId()) // 代表这个JWT的签发主体;
.setIssuedAt(new Date()) // 是一个时间戳,代表这个JWT的签发时间;
.setAudience(audience.getName()) // 代表这个JWT的接收对象;
.signWith(signatureAlgorithm, signingKey);
//添加Token过期时间
int TTLMillis = audience.getExpiresSecond();
if (TTLMillis >= 0) {
long expMillis = nowMillis + TTLMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp) // 是一个时间戳,代表这个JWT的过期时间;
.setNotBefore(now); // 是一个时间戳,代表这个JWT生效的开始时间,意味着在这个时间之前验证JWT是会失败的
}
//生成JWT
return builder.compact();
} catch (Exception e) {
log.error("签名失败", e);
throw new CustomException(ResultCode.PERMISSION_SIGNATURE_ERROR);
}
}
/**
* 从token中获取用户名
* @param token
* @param base64Security
* @return
*/
public static String getUsername(String token, String base64Security){
return parseJWT(token, base64Security).getSubject();
}
/**
* 从token中获取用户ID
* @param token
* @param base64Security
* @return
*/
public static String getUserId(String token, String base64Security){
String userId = parseJWT(token, base64Security).get("userId", String.class);
return Base64Util.decode(userId);
}
/**
* 是否已过期
* @param token
* @param base64Security
* @return
*/
public static boolean isExpiration(String token, String base64Security) {
return parseJWT(token, base64Security).getExpiration().before(new Date());
}
}
拦截器:
@Autowired
private Audience audience;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 忽略带JwtIgnore注解的请求, 不做后续token认证校验
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
JwtIgnore jwtIgnore = handlerMethod.getMethodAnnotation(JwtIgnore.class);
if (jwtIgnore != null) {
return true;
}
}
if (HttpMethod.OPTIONS.equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
// 获取请求头信息authorization信息
final String authHeader = request.getHeader(JwtTokenUtil.AUTH_HEADER_KEY);
log.info("## authHeader= {}", authHeader);
if (StringUtils.isBlank(authHeader) || !authHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)) {
log.info("### 用户未登录,请先登录 ###");
throw new CustomException(ResultCode.USER_NOT_LOGGED_IN);
}
// 获取token
final String token = authHeader.substring(7);
if(audience == null){
BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
audience = (Audience) factory.getBean("audience");
}
// 验证token是否有效--无效已做异常抛出,由全局异常处理后返回对应信息
JwtTokenUtil.parseJWT(token, audience.getBase64Secret());
return true;
}
发现了,以下问题:
1.没有对输入ID进行加密
2.没有用logger记录日志
3.JWT配置应该在配置文件中设置
4.没有设置过期时间,不过我的token是放在cookie当中,cookie设置了过期时间
5.密钥设置过于简单
这些打算在之后的项目进行修改
评论