SpringBoot集成JWT实现token,与session的区别
JWT是什么
Json web token,它是一种紧凑且独立的方法,用于在各方之间安全地将信息作为JSON对象传输。 由于此信息是经过数字签名的,因此可以被验证和信任。
JWT的结构
头部信息
载荷信息
签名信息
- 加密算法常见的有MD5、SHA256、HAMC。
SpringBoot和JWT的集成
- 引入依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
public class JWTUtil {
public static String createToken(String userId,String password,int timeType,int timeValue) {
Calendar nowTime = Calendar.getInstance();
nowTime.add(timeType,timeValue);
Date expiresDate = nowTime.getTime();
return JWT.create().withAudience(userId.toString())
.withIssuedAt(new Date())
.withExpiresAt(expiresDate)
.sign(Algorithm.HMAC256(password));
}
public static void verifyToken(String token, String secret) {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
DecodedJWT jwt = verifier.verify(token);
}
public static String getAudience(String token) throws GlobalHandleException {
String audience = null;
try {
audience = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new GlobalHandleException(ResultCode.USER_AUTHENTICATION_ERROR);
}
return audience;
}
}
- 配置拦截器
public class JWTInterceptor extends HandlerInterceptorAdapter {
@Resource
private IUserInfoService userInfoService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if(!(handler instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod=(HandlerMethod)handler;
Method method=handlerMethod.getMethod();
//检查是否有UserValid注释,没有则跳过认证
if (!method.isAnnotationPresent(UserValid.class)) {
return true;
}
if(token == null){
writeValueAsString(response,Result.fail(ResultCode.USER_NOT_LOGGED_IN));
return false;
}
String userId;
try {
userId = JWTUtil.getAudience(token);
} catch (GlobalHandleException j) {
writeValueAsString(response, Result.fail(ResultCode.USER_NOT_LOGGED_IN));
return false;
}
UserInfoBean userInfoBean = userInfoService.getById(userId);
if(userInfoBean == null){
writeValueAsString(response,Result.fail(ResultCode.USER_NOT_EXIST));
return false;
}
// 验证 token
try {
JWTUtil.verifyToken(token,userInfoBean.getUserPass());
} catch (TokenExpiredException e) {
writeValueAsString(response,Result.fail(ResultCode.TOKEN_EXPIRED));
return false;
}catch (Exception e) {
writeValueAsString(response,Result.fail(ResultCode.USER_AUTHENTICATION_ERROR));
return false;
}
request.setAttribute("user",userInfoBean);
return true;
}
private void writeValueAsString(HttpServletResponse response, Result result) throws IOException {
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(mapper.writeValueAsString(result));
}
}
配置realm
public class JWTRealm extends AuthorizingRealm {
@Resource
private IUserInfoService userInfoService;
@Resource
private IFunctionInfoService functionInfoService;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JWTToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取当前登录的用户
UserInfoBean userInfoBean = (UserInfoBean) principalCollection.getPrimaryPrincipal();
//通过SimpleAuthenticationInfo做授权
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
List<RoleInfoBean> roleInfoBeans = userInfoBean.getRoleInfoBeans();
List<FunctionInfoBean> functionInfoBeans = functionInfoService.selectByRoleId(roleInfoBeans);
for (RoleInfoBean role : roleInfoBeans) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
}
for (FunctionInfoBean function : functionInfoBeans) {
//添加权限
simpleAuthorizationInfo.addStringPermission(function.getFuncName());
}
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String token = (String) authenticationToken.getPrincipal();
if(token == null){
return new SimpleAuthenticationInfo(null,"",getName());
}
UserInfoBean userInfoBean = null;
try {
userInfoBean = WebUtil.verifyToken(token,userInfoService);
} catch (GlobalHandleException e) {
}
if(userInfoBean == null){
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userInfoBean,token,getName());
return simpleAuthenticationInfo;
}
}
配置JWTToken
public class JWTToken implements AuthenticationToken {
private String token = "";
public JWTToken(String token){
if(token != null){
this.token = token;
}
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
JWT与session的比较
Session:
session每次产生对象和sessionId,将sid存放到浏览器的cookies,每次浏览器请求都会带上sid,与服务器进行键值对匹配,用于验证用户的状态。
-
存在问题
1、session对象保存在服务端,服务端压力大。
2、sid保存在cookies不安全,容易被盗用。 -
JWT的优点:
1.简洁: 因为数据量小,传输速度也很快
2.Token是以JSON加密的形式保存在客户端的
3.不需要在服务端保存对象信息。