JWT工具类:
什么是jwt:json wen token,是一种无状态的验证登陆是否合法的一种校验规则,以前我们使用session,只能在单独的服务器使用(tomcat也可以session共享,但是浪费性能,需要在每个服务器都存储一份),后来我们还可以使用redis,生成token为key,用户信息为value,每次客户登陆都去redis查询,这也是微服务之间session共享的解决方案。
除了redis,我们还可以使用jwt解决,客户登陆之后,按照规则,生成一个令牌(token),不在服务端存储,而是只在客户端存储,每次客户访问,都携带这个token,后端可以通过解密的方式,把此token解析,获取里面存放的客户信息,即可完成校验。
简单来说: 就是通过一定规范来生成token,然后可以通过解密算法逆向解密token,这样就可以获取用户信息
一.jwt生成token的组成部分:
- 第一段HEADER部分,固定包含算法和token类型,对此json进行base64url加密,这就是token的第一段。
{
"alg": "HS256",
"typ": "JWT"
}
- 第二部分PLAYLOAD部分,包含一些数据,对此json进行base64url加密,这就是token的第二段。也可以称载荷(就是客户的信息)
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
...
}
- 第三段SIGNATURE部分,把前两段的base密文通过·拼接起来,然后对其进行HS256加密,再然后对HS256密文进行base64url加密,最终得到token的第三段。
base64url(
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
your-256-bit-secret (密钥加盐)
)
)
其实就是先跟base64把header和payload加密,并通过.连接,之后,再按照指定的加密规则,把上边加密后的字符串和我们提供的密钥,再次加密,获得token
二.案例(基于java实现jwt):
- jwt工具类:
/**
* jwt工具类
*/
public class JWTUtils {
/**
* 声明过期时间 毫秒 一天之后失效
*/
private static final long EXPIRE = 60000 * 60 * 24;
/**
* 加密的公用密钥
*/
private static final String SECRET = "chenerhao";
/**
* 颁布者
*/
private static final String SUBJECT = "com.ceh";
/**
* 加密生成jwt令牌
*/
public static String geneJsonWebToken(User user){
return Jwts.builder().setSubject(SUBJECT) //设置住体(颁布者)
.claim("name",user.getName()) //设置荷载
.claim("id",user.getId()) //设置荷载
.claim("hand_img",user.getHeadImg())//设置荷载
.setIssuedAt(new Date())//设置生成时间
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))//设置过期时间
.signWith(SignatureAlgorithm.HS256,SECRET)//使用HS256算法,加密密钥
.compact();//生成最终的token令牌
}
/**
* 解密token
*/
public static Claims checkJWT(String token){
try{
Claims claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
return claims;
}catch (Exception e){
//当出现任何的异常,都代表此token解析失败,不是正常的token
return null;
}
}
}
- 登陆完毕,生成token令牌:
//登陆service
@Override
public String login(User user) {
if(user == null){
throw new MyException(ExceptionEnum.PARAM_IS_NULL);
}
String phone = user.getPhone();
String pwd = user.getPwd();
//对密码加密
String md5Pwd = MD5Utils.MD5(pwd);
User resultUser = userDao.doLogin(phone, md5Pwd);
if(resultUser == null){
//登陆失败
throw new MyException(ExceptionEnum.LOGIN_ERROR);
}
//登陆成功 生成token
String token = JWTUtils.geneJsonWebToken(resultUser);
return token;
}
- 解析token:
这里我才用的是拦截器,拦截请求,并判断是否携带token
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
//获取请求头中的token
String token = request.getHeader("token");
if(StringUtils.isEmpty(token)){
//为空之后判断请求参数中是否有
token = request.getParameter("token");
}
//判断token是否有值
if(StringUtils.isEmpty(token)){
//没有token
throw new MyException(ExceptionEnum.TOKEN_ERROR);
//return false;
}
//有token 解析
Claims claims = JWTUtils.checkJWT(token);
if(claims != null){
//成功解析
//获取user信息
Integer id = (Integer) claims.get("id");
String name = (String) claims.get("name");
request.setAttribute("id",id);
request.setAttribute("name",name);
return true;
}
throw new MyException(ExceptionEnum.TOKEN_ERROR);
}
}
注意:jwt是按照一定的加密算法,加密成一个token,所有token不具备保证数据的安全性,他只是用来认证用户的来源是否是合法用户
如果要保证数据安全性,可以使用https,不使用http请求
jwt如何实现logout:
因为token存储在客户端,后台无法操作,但是我们设置的有过期时间
1.等待时间自动失效
2。后台设置黑名单,退出时,加入到黑名单中,每次请求,都去黑名单校验是否当前token存在黑名单中。