需求
- SpringBoot项目集成JWT,实现Token验证,保存用户登录状态。
- 项目已上传到github,欢迎参考~
- https://github.com/ABCVBNM/jwt_demo.git
实现
1. 添加依赖
这里选择的是jwtk/jjwt(因为看github上的Java_JWT项目,该项目维护最及时,星星最多)
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<!-- Uncomment this next dependency if you are using JDK 10 or earlier and you also want to use
RSASSA-PSS (PS256, PS384, PS512) algorithms. JDK 11 or later does not require it for those algorithms:-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
<scope>runtime</scope>
</dependency>`
2. 编写编写TokenUtils类
1. 添加生成Token方法getToken
2. 添加解析Token方法parseToken
3. 添加验证Token方法verifyToken
因为要适配的项目业务不多,所以将用户信息保存在静态变量中,实现缓存的效果,每次解析Token都会进行对比。
public String getToken(User user) {
// String jws = Jwts.builder().setSubject(user.getUserName()).setExpiration(new Date(System.currentTimeMillis() + 3600 * 24 * 1000)).signWith(key).compact();
user.setPassWord("");
// user.setUserName("");
Claims claims = Jwts.claims();
claims.put("user", user);
userName = user.getUserName();
admin = user.getAdmin();
warehouseName = user.getWarehouseName();
String jws = Jwts.builder().setClaims(claims).setExpiration(new Date(System.currentTimeMillis() + 3600 * 24 * 1000)).signWith(key).compact();
return jws;
}
public HashMap parseToken(String token) {
try {
LinkedHashMap userMap = (LinkedHashMap) Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody().get("user");
return userMap;
} catch (ExpiredJwtException e) {
e.printStackTrace();
} catch (UnsupportedJwtException e) {
e.printStackTrace();
} catch (MalformedJwtException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
return null;
}
// 拦截器用
public boolean verifyToken(String token) {
HashMap map = parseToken(token);
if (map == null) return false;
if (map.get("userName").equals(userName) || map.get("admin").equals(admin) || map.get("warehouseName").equals(warehouseName))
return true;
return false;
}
3. 添加过滤器
拦截请求,调用Tokenutil进行token校验,校验失败返回401。
SpringBoot中编写过滤器,只需要实现HandlerInterceptor接口即可。
@Component
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Resource(name = "tokenUtilService")
TokenUtilService tokenUtilService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("L_Token");
if (token == null || !tokenUtilService.verifyToken(token)) {
response.setStatus(401);
response.getWriter().print("无效的Token,请重新登录!");
response.getWriter().flush();
return false;
}
return true;
}
// todo: print logs
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
4. 添加配置类,配置过滤器
excludePath中添加需要放行的请求,这里边只添加了login
@Configuration
public class LoginInterceptConf implements WebMvcConfigurer {
@Resource
LoginHandlerInterceptor loginHandlerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginHandlerInterceptor).excludePathPatterns("/login");
}
}
5. 编写登陆类
1. 实现登录接口
2. 实现根据Token获取用户信息接口
@Controller
public class Login {
public static String userName = "li";
public static String passWord = "lei";
public static String admin = "1";
@Resource(name = "tokenUtilService")
TokenUtilService tokenUtilService;
@RequestMapping(method = RequestMethod.POST, value = "/login")
@ResponseBody
public String login(@RequestBody User user) {
Result result = new Result();
if (user.getUserName().equals(userName) && user.getPassWord().equals(passWord)) {
user.setAdmin(admin);
user.setWarehouseName("深圳实验室");
result.setMsg("success!");
result.setCode("200");
result.setToken(tokenUtilService.getToken(user));
} else {
result.setMsg("fail");
result.setCode("404");
}
return JSON.toJSONString(result);
}
@RequestMapping(method = RequestMethod.POST, value = "/getUserInfo")
@ResponseBody
public HashMap getUserInfoByToken(String token) {
HashMap map = tokenUtilService.parseToken(token);
return map;
}
}