前言
本篇使用java-jwt作为JWT库,与Spring Boot整合实现前后端分离架构中用户认证。
Spring Boot项目搭建参考:
[Spring Boot系列]1. 项目搭建之一
关于JWT的介绍参考:
JWT介绍以及java-jwt的使用
整合思路
- 后端提供登录服务,根据前端POST的用户名、密码产生Token。
- 对用户名、密码验证通过后产生Token
- Token中包含用户名、过期时间,使用用户密码作为密钥进行加盐加密。
- 前端获取该Token后,随后的请求附加该Token,后端获取Token解密,获取用户名,并且验证Token是否有效
实例步骤和代码
- 在pom.xml中导入JWT
<!--JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.3</version>
</dependency>
- 提供产生Token的服务,这里使用 /login, 控制器类是PermissController
@RestController
public class PermissController {
@Autowired
private UserService userService;
@Autowired
private PermissService permissService;
@Autowired
private BadouMessages badouMessages;
@SuppressWarnings({ "rawtypes", "unchecked" })
@PostMapping("/login")
public Object login(@RequestBody User user) {
StatusResponse statusResponse = new StatusResponse(Status.SUCCESS, null);
if (user != null && user.getId() != null) {
User userFromDb = userService.get(user.getId());
if (userFromDb == null) {
statusResponse.setMessage(badouMessages.get("userNotExist", new String[] { user.getId() }));
statusResponse.setStatus(Status.FAIL);
} else {
if (!userFromDb.getPassword().equals(user.getPassword())) {
statusResponse.setMessage(badouMessages.get("userNotExist", new String[] { user.getId() }));
statusResponse.setStatus(Status.FAIL);
} else {
Map map = new HashMap();
String token = permissService.getToken(userFromDb);
map.put("token", token);
map.put("user", userFromDb);
return map;
}
}
} else {
statusResponse.setMessage(badouMessages.get("nullMsg", new String[] { "User Id" }));
statusResponse.setStatus(Status.FAIL);
}
return statusResponse;
}
}
- 定义拦截器拦截验证Token
/**
* @Title: AuthenticationInterceptor.java
* @Package com.osxm.badou.base
* @Description: TODO
* @author oscarchen
* @date 2019年10月25日
* @version V1.0
*/
package com.osxm.badou.base;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.osxm.badou.base.BadouConstants.Status;
import com.osxm.badou.base.service.PermissService;
/**
* @ClassName: AuthenticationInterceptor
* @Description: TODO
* @author oscarchen
*/
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
PermissService permissService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object object) throws Exception {
String token = httpServletRequest.getHeader("token");
String errMsg = null;
// 非映射方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
//
if (token == null) {
errMsg = "没有token,请登录";
} else {
try {
permissService.verifyToken(token);
} catch (BadouException e) {
errMsg = e.getMessage();
}
}
if (errMsg != null) {
StatusResponse statusResponse = new StatusResponse(Status.FAIL, errMsg);
ResponseUtil.returnJsonMessage(httpServletResponse, statusResponse);
return false;
}
return true;
}
}
- 配置拦截器拦截需要验证用户的请求
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor()).addPathPatterns("/demos");
}
@Bean
public AuthenticationInterceptor authInterceptor() {
return new AuthenticationInterceptor();
}
}
- 加密、解密Token的服务代码
@Service
public class PermissServiceImpl implements PermissService {
@Autowired
private BadouMessages dadouMessages;
@Autowired
private UserService userService;
public String getToken(User user) {
String token = "";
token = JWT.create().withAudience(user.getId())// 把用户ID存入Token
.sign(Algorithm.HMAC256(user.getPassword()));// 用户密码作为密钥,使用HMAC(消息散列鉴别码)算法加密生成Token
return token;
}
public User verifyToken(String token) throws BadouException {
User user = getUser(token);
if (user != null) {
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new BadouException(dadouMessages.get("invalidtoken"));
}
} else {
throw new BadouException(dadouMessages.get("invalidtoken"));
}
return user;
}
private User getUser(String token) {
User user = null;
try {
String userId = JWT.decode(token).getAudience().get(0);
user = userService.get(userId);
user.setId(userId);
} catch (JWTDecodeException j) {
}
return user;
}
}
示例项目Git路径。
待补充,或私信索取
如需详细了解相关机制和代码参考,参见
前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之一