论坛项目核心功能点
分布式情况下的session
采用方案:Jwt+Redis
Jwt工具类,用于生成jwt和解析jwt
package com.yxh.island.util;
/****
包含 header
jwt的头部承载两部分信息:
声明类型,这里是jwt
声明加密的算法 通常直接使用 HMAC SHA256
playload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
标准中注册的声明
公共的声明
私有的声明
signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
****/
public class JwtHelper {
//头部base64 对称加密
private final static String base64Secret = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=";
//过期时间
private final static int expiresSecond = 172800000;
public static Claims parseJWT(String jsonWebToken) {
try {
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(base64Secret))
.parseClaimsJws(jsonWebToken).getBody();
return claims;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
public static String createJWT(Usermin user, Long time) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//生成签名密钥
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Secret);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
.claim("id", user.getId())
.claim("userid", user.getUserid())
.claim("time", time)
.claim("userpic",user.getUserpic() )
.claim("useremail", user.getUseremail())
.signWith(signatureAlgorithm, signingKey);
//添加Token过期时间
if (expiresSecond >= 0) {
long expMillis = nowMillis + expiresSecond;
Date exp = new Date(expMillis);
builder.setExpiration(exp).setNotBefore(now);
}
//生成JWT
return builder.compact();
}
}
这样我们就可以通过传输jwt来安全的获取user的信息了,并且有过期时间,好像看上去是没问题了
但是,真的是这样嘛?
第一次考虑的用户登录流程
用户登录-> 返回jwt -> 使用jwt完成业务
完成业务的过程中:
url 拼接jwt ->后端验证 ->返回结果
那如果这个业务没问题,下次业务的时候时间过期了,是不是又要重新登录,会不会影响用户使用呢?
因此我们考虑每次业务后增加用户过期的时间,提升用户体验
第二次考虑的用户登录流程
url 拼接jwt ->后端验证 成功,加过期时间->返回结果
但我们考虑这样一个场景,如果你在你的电脑上登录了,有另外一个人在另外一个电脑上登录了,是不是第一个登录的账号应该被挤下来?
所以我们要保证一个全局的,只有一个人登录的情况下就只能上第三方的中间件了。
我们在redis中已userid为key存一个 用户的登录时间,每次重新登录的时候刷新redis中的 session,用户传token 的时候我们验证他的jwttoken是不是和redis的时间一致就好了。
所以用户要直接登录的条件就是jwt未过期,redis未过期
我们可以考虑每次都把jwt过期时间快过期的时候加长 ,所以redis我们默认过期时间最好设置的比jwt长一点