JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库。
首先看下JWT的流程图:
身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录(SSO)中比较广泛的使用了该技术。 信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。
在SpringMVC中使用的步骤:
1.创建JWT工具类
public class jwtUtil {
private static Logger logger = LoggerFactory.getLogger(jwtUtil.class);
private static final String SECRET = "你的秘钥";
private static final long EXPIRATION_TIME = 1 * 24 * 60 * 60 * 1000; //有效期
/**
* HS256加密
* @return
* @throws Exception
*/
public static String createTokenHS256(String subject) throws Exception{
String token="";
try {
long nowMillis = System.currentTimeMillis();
long expMillis = nowMillis + EXPIRATION_TIME;
Date exp = new Date(expMillis);
Algorithm algorithm = Algorithm.HMAC256(SECRET);
token = JWT.create()
.withSubject(subject)
.withIssuer("demo")
.withExpiresAt(exp)
.sign(algorithm);
} catch (JWTCreationException exception){
logger.error("HS256加密异常",exception.getMessage());
}
return token;
}
/**
* HS256解密
* @param token
* @throws Exception
*/
public static String verifyTokenHS256(String token) throws Exception{
String subject="";
try {
Algorithm algorithm = Algorithm.HMAC256(SECRET);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("demo")
.build();
subject = verifier.verify(token).getSubject();
} catch (JWTVerificationException exception){
logger.error("HS256解密异常",exception.getMessage());
}
return subject;
}
}
2.创建拦截器
public class TokenInterceptor implements HandlerInterceptor {
/**
* 拦截每个请求
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {
response.setCharacterEncoding("utf-8");
String token = request.getParameter("token");
String userId= request.getParameter("userId");
//token存在
if(null != token) {
String subject=jwtUtil.verifyTokenHS256(token);
if(!StringUtils.isEmpty(subject) && !StringUtils.isEmpty(userId)){
if(userId.equals(subject)) {
return true;
}
else{
responseMessage(response, response.getWriter(), "请求未通过");
return false;
}
}
else{
responseMessage(response, response.getWriter(), "请求未通过");
return false;
}
}
else{
responseMessage(response, response.getWriter(), "请求未通过");
return false;
}
}
/**
* 请求不通过,返回错误信息给客户端
* @param response
* @param out
* @param responseData
*/
private void responseMessage(HttpServletResponse response, PrintWriter out, String responseMsg) {
response.setContentType("application/json; charset=utf-8");
out.print(responseMsg);
out.flush();
out.close();
}
}
3.在springmvc-servlet.xml中配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/user/register" />
<mvc:exclude-mapping path="/user/login" />
<bean class="com.demo.interceptor.TokenInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
4.登录时调用jwtUtil生成token,并封装进用户对象返回前端,前端调用后台接口带上userId和token即可。