SpringBoot整合JWT
概述
有关jwt
的的详细概述请参考阮一峰博客入门教程:https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
整合
导包–采用
java-jwt
jar包
<!-- jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
<!--Hutool Java工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.0</version>
</dependency>
编写jwt工具类
/**
* jwt工具类
*
* @Author nanfeng
*/
@Slf4j
public class JwtTokenUtil {
private final static Long expiration = 72000000L;
private final static String tokenHeader = "Authorization";
private final static String secret = "secret";
/**
* 校验 token是否正确
*
* @param token 密钥
* @return 是否正确
*/
public static boolean verify(String token, String username) {
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username)
.build();
verifier.verify(token);
log.info("token is valid");
return true;
} catch (TokenExpiredException e) {
throw new BaseException(HttpStatus.HTTP_UNAUTHORIZED,"登录过期,请重新登录");
} catch (Exception e) {
log.info("token is invalid {}", e.getMessage());
throw new BaseException(e.getMessage());
}
}
/**
* 从 token中获取用户名
*
* @return token中包含的用户名
*/
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
log.error("error:{}", e.getMessage());
throw new JWTDecodeException(e.getMessage());
}
}
/**
* 生成 token
*
* @param username 用户名
* @return token
*/
public static String sign(String username) {
try {
username = StringUtils.lowerCase(username);
Date date = new Date(System.currentTimeMillis() + expiration * 1000);
Algorithm algorithm = Algorithm.HMAC256(secret);
return JWT.create()
.withClaim("username", username)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
log.error("error:{}", e);
throw new BaseException(e.getMessage());
}
}
/**
* 获取请求token
*
* @param request
* @return token
*/
public static String getToken(HttpServletRequest request) {
String requestHeader = request.getHeader(tokenHeader);
String token = null;
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
token = requestHeader.substring(7);
}
return token;
}
}
token拦截器
/**
* jwt 过滤器
*
* @Author nanfeng
*/
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 跨域时会首先发送一个 option请求,这里我们给 option请求直接返回正常状态
if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
response.setStatus(HttpStatus.HTTP_OK);
return true;
}
response.setCharacterEncoding("utf-8");
String username = null;
String authToken = JwtTokenUtil.getToken(request);
if (StrUtil.isNotBlank(authToken)) {
username = JwtTokenUtil.getUsername(authToken);
}
if (StrUtil.isNotBlank(username)) {
User user = userService.findByName(username);
if (JwtTokenUtil.verify(authToken, user.getUsername())) {
return true;
}
}
return false;
}
}
配置不需验证的请求
/**
* 请求拦截器,配置不拦截请求
*
* @Author nanfeng
* @Date 2021/4/7 15:26
*/
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login")
.excludePathPatterns("/doc.html/**","/swagger-resources/**", "/webjars/**", "/v2/**");
}
}
编写登录接口
@RestController
@Api(tags = "登录接口")
public class LoginController {
@Autowired
private LoginService loginService;
@PostMapping(value = "/login")
@ApiOperation(value = "登录",notes = "username,password,code")
public AjaxResult login(@RequestBody LoginBody loginBody){
Map<String, Object> map = new AjaxResult();
String token = loginService.verify(loginBody);
map.put("token", token);
return AjaxResult.success(map);
}
}
登录验证
@Component
@Slf4j
public class LoginService {
@Autowired
private UserService userService;
public String verify(LoginBody loginBody) {
String encryptPassword = DigestUtil.md5Hex(loginBody.getPassword());
User user = userService.findByName(loginBody.getUsername());
if (ObjectUtil.isNull(user)) {
throw new BaseException("该用户名不存在");
} else {
if (!StrUtil.equals(user.getPassword(), encryptPassword)) {
throw new BaseException(HttpStatus.HTTP_UNAUTHORIZED, "用户名或密码错误");
}
return JwtTokenUtil.sign(loginBody.getUsername());
}
}
}
整合过程用到的统一结果输出
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/** 数量长度 */
public static final String TOTAL_TAG = "total";
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (ObjectUtil.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
public AjaxResult(int code, String msg, Long total, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
super.put(TOTAL_TAG,total);
if (ObjectUtil.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data)
{
return AjaxResult.success("操作成功", data);
}
/**
* 分页查询返回
* @param total
* @param data
* @return
*/
public static AjaxResult success(Long total,Object data){
return AjaxResult.totalSuccess("操作成功",total,data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
{
return new AjaxResult(HttpStatus.HTTP_OK, msg, data);
}
/**
* 返回分页成功消息
* @param msg
* @param total
* @param data
* @return
*/
public static AjaxResult totalSuccess(String msg,Long total,Object data)
{
return new AjaxResult(HttpStatus.HTTP_OK, msg,total,data);
}
/**
* 返回错误消息
*
* @return
*/
public static AjaxResult error()
{
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult error(String msg)
{
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult error(String msg, Object data)
{
return new AjaxResult(HttpStatus.HTTP_INTERNAL_ERROR, msg, data);
}
/**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult error(int code, String msg)
{
return new AjaxResult(code, msg, null);
}
}
结果
{
"msg": "操作成功",
"code": 200,
"data": {
"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxx.neWhVBM0Vx9hBHYPjyS3dXoJ0rhdpwOUofsGZA3URrA"
}
}