JWT的全称叫Json Web Token。JSON Web Token是一个开放标准(RFC 7519),该Token被设计为紧凑且安全的,用于在各方之间作为JSON对象安全地传输信息。由于信息是经过数字签名的,因此可以进行验证和信任。客户端只需使用一次凭据即可向服务器进行身份验证。在此期间,服务器验证凭据,并向客户端返回JWT。对于以后的所有请求,客户端可以使用这个Token向服务器进行身份验证,就不需要发送用户名和密码之类的凭据。
JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:Header、Payload、Signature。
Header:描述了JWT元数据,是一个 JSON 对象,它的格式如下:
{"alg":"HS256","typ":"JWT"}
alg属性表示签名所使用的算法,通常直接使用 HMAC SHA256。typ 属性表示令牌类型,这里就是 JWT。
Payload:就是存放有效信息的地方。这些有效信息包含以下三个部分
标准中注册的声明
ss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识
公共的声明
在这里我们可以添加任何信息。
私有的声明
私有声明是服务器和客户端共同定义的声明
Signature:这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密。
最终形成了如下字符。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTQ4Nzk2OTksInVzZXJuYW1lIjoiYSJ9.OYmhA25LE8Ujq3U8FYTG72PptbqglkAYBacnv3kjuj4"
<dependency>
<groupId>com.auth0groupId>
<artifactId>java-jwtartifactId>
<version>3.4.0version>
dependency>
首先在application.properties中配置一个secret。
jwt.secret=abcdplokiahsfgdma
@Configuration
public class JwtConfig {
@Value("${jwt.secret}")
private String secret;
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}
Controller
package com.hxl.springbootdemo.controller;
import com.hxl.springbootdemo.config.JwtConfig;
import com.hxl.springbootdemo.entity.R;
import com.hxl.springbootdemo.entity.User;
import com.hxl.springbootdemo.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
JwtConfig jwtConfig;
@PostMapping(value="/login")
@ResponseBody
public R login(String username, String password){
/**
* 省略判断用户名密码
*/
User user = new User(username,password);
String token = JwtUtils.sign(user,jwtConfig);
return new R(0,"登录成功",token);
}
@PostMapping(value="/list")
@ResponseBody
public R list(User user){
System.out.println(user);
return new R(0,"登录成功","data");
}
}
创建一个拦截器,拦截没有登录的用户。
package com.hxl.springbootdemo.interceptors;
import com.auth0.jwt.interfaces.Claim;
import com.hxl.springbootdemo.config.JwtConfig;
import com.hxl.springbootdemo.exts.SystemException;
import com.hxl.springbootdemo.utils.JwtUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class AuthenticationInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(AuthenticationInterceptor.class);
@Autowired
JwtConfig jwtConfig;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
if (token==null || token.length()==0){
throw new SystemException("未登录");
}
logger.info("认证{}",token);
Map<String, Claim> verify = JwtUtils.verify(token, jwtConfig);
if (verify==null){
throw new SystemException("用户身份验证失败");
}
return true;
}
}
JwtUtils用来创建JWT和验证。
package com.hxl.springbootdemo.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.hxl.springbootdemo.config.JwtConfig;
import com.hxl.springbootdemo.entity.User;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
public static String sign(User user, JwtConfig jwtConfig){
String token = null;
try {
LocalDate localDate =LocalDate.now();
localDate.plusDays(1);
Date expir = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
token = JWT.create()
/**
* 用户信息
*/
.withClaim("username", user.getName())
/**
* 过期时间
*/
.withExpiresAt(expir)
/**
* 签名
*/
.sign(Algorithm.HMAC256(jwtConfig.getSecret()));
} catch (Exception e){
e.printStackTrace();
}
return token;
}
public static Map<String, Claim> verify(String token, JwtConfig jwtConfig){
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(jwtConfig.getSecret())).build();
DecodedJWT jwt = verifier.verify(token);
return jwt.getClaims();
} catch (Exception e){
return null;
}
}
}
自定义一个参数转换器。
package com.hxl.springbootdemo.handler;
import com.auth0.jwt.interfaces.Claim;
import com.hxl.springbootdemo.config.JwtConfig;
import com.hxl.springbootdemo.entity.User;
import com.hxl.springbootdemo.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import java.util.Map;
public class UserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
JwtConfig config;
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType().equals(User.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
String token = nativeWebRequest.getHeader("token");
Map<String, Claim> verify = JwtUtils.verify(token, config);
return new User(verify.get("username").asString(),"");
}
}
配置拦截器和参数转换器。
package com.hxl.springbootdemo.config;
import com.hxl.springbootdemo.handler.UserHandlerMethodArgumentResolver;
import com.hxl.springbootdemo.interceptors.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(createAuthenticationInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
@Bean
public AuthenticationInterceptor createAuthenticationInterceptor(){
return new AuthenticationInterceptor();
}
@Bean
UserHandlerMethodArgumentResolver createUserHandlerMethodArgumentResolver(){
return new UserHandlerMethodArgumentResolver();
}
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(createUserHandlerMethodArgumentResolver());
}
}
全局异常处理。
@RestControllerAdvice
public class ErrorController {
@ExceptionHandler(Exception.class)
public R handlerException(Exception e){
return new R(-1,e.getMessage(),"{}");
}
}