本篇文章主要介绍了JWT是什么、JWT的作用、JWT的组成、如何生成JWT令牌、如何校验JWT令牌、JWT令牌在实际项目开发中利用场景、以及通过HandlerInterceptor拦截器统一拦截请求校验JWT令牌。
目录
JWT概念:
JWT是什么?
JWT作用:
JWT组成:
JWT利用:
生成JWT:
校验JWT:
注意事项:
实际项目开发中利用场景:
application.yml中配置密钥:
JWTUtil工具类:
用户登录接口生成JWT令牌:
配置拦截器拦截请求校验JWT令牌:
拦截器注册到registry中:
JWT概念:
JWT是什么?
JWT(Json Web Token) 是通过数字署名的方式,以json为载体,在差别的服务之间安全的传输信息的技能,定义了一种简洁的、自包罗的格式,用于通信两边以json数据格式安全的传输信息。
JWT令牌就是一段字符串:承载业务数据,减少后续请求查询数据库的次数(令牌包罗用户信息,需要用户信息时无需再次查询数据库,在令牌中获取用户信息数据即可)。
JWT作用:
一样平常在授权认证的过程中,一旦用户登录,后端返回一个token给前端,这个token相当于前端访问后端服务的令牌,前端向后端发送的每一个请求都需要包罗这个token,后端会通过拦截器拦截请求获取token并举行安全校验,校验通过才执行具体的业务逻辑。
Token诞生在服务器端,由浏览器生存着的,持有token就像持有“令牌”一样答应访问服务器。
JWT组成:
JWT由三部门组成的,以点分开:header.payload.signature
第一部门:Header(头),记录令牌类型,署名算法(用于防窜改),例如:{“alg”:”HS256”, “type”:“JWT”}
第二部门:Payload(有效载荷),可以存放一些自定义信息(不能存放私密数据因为这里的数据是没有被加密过的),例如:{“id”:”1”, “username”:“Tom”}
第三部门:Signature(署名),存放署名信息,防止Token被窜改、确保安全性。
JWT利用:
生成JWT:
1、引入依靠:
- <dependency>
- <groupId>com.auth0</groupId>
- <artifactId>java-jwt</artifactId>
- <version>4.4.0</version>
- </dependency>
复制代码 2、调用API生成JWT令牌:
校验JWT:
注意事项:
JWT校验时利用的署名密钥,必须和生成JWT令牌时利用的密钥是匹配的。
假如JWT令牌剖析校验时报错:
1、假如窜改了头部和载荷部门的数据,那么验证失败
2、假如密钥不对,验证失败
3、token过期
实际项目开发中利用场景:
application.yml中配置密钥:
- jwt:
- secret-key: xiyangyang
复制代码 JWTUtil工具类:
生成JWT令牌时添加载荷(自定义一些业务数据记任命户信息),配置过期时间,指定署名算法并配置密钥。
校验JWT令牌,因为加密时利用的加密算法是对称加密,加密算法和解密算法以及加密密钥和解密密钥是同一个。
- public class JWTUtil {
- // 生成JWT
- public static String getToken(Map<String, Object> claims, String secretKey) {
- String token = JWT.create()
- .withClaim("claims", claims) // 添加载荷
- .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 添加过期时间 一个小时
- .sign(Algorithm.HMAC256(secretKey)); // 指定算法,配置密钥
- return token;
- }
- // JWT验证
- public static Map<String ,Object> parseToken(String token, String secretKey) {
- // 加密算法和解密算法、加密密钥和解密密钥都是同一个(对称加密)
- JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secretKey)).build();
- // 验证token,生成一个解析后的JWT对象
- DecodedJWT decodedJWT = jwtVerifier.verify(token);
- // 获取JWT的所有的载荷
- Map<String, Claim> claims = decodedJWT.getClaims();
- return claims.get("claims").asMap();
- }
- }
复制代码 用户登录接口生成JWT令牌:
在用户登录接口中起首根据用户名查询数据库判断是否能查询到用户信息从而判断用户名是否正确,若用户名正确之后对请求参数中的暗码举行加密判断加密后的暗码是否和刚刚获取到的用户信息中的暗码一致(数据库中的暗码都是加密存储的)。若用户名和暗码都正确则生成JWT令牌返回给用户,并在JWT令牌中承载业务数据记录部门用户信息以便后续请求接口中利用。
- @RequestMapping(method = RequestMethod.POST, value = "/login")
- public ResultDTO login(
- @Size(min = 5, max = 16) String username,
- @Size(min = 5, max = 16) String password
- ) {
- // 根据用户名获取用户信息
- UserDTO userInfo = userService.getUserInfoByUserName(username);
- if (userInfo == null) {
- return ResultDTO.error("用户名不存在");
- }
- // 判断请求参数中的用户密码加密后是否和数据库中用户密码一致
- Boolean passwordIsTrue = userService.judgePassWordIsTrue(userInfo, password);
- if (passwordIsTrue) {
- // 生成JWT令牌返回给用户, 并承载业务数据记录部分用户信息
- Map<String, Object> userInfoMap = new HashMap<>();
- userInfoMap.put("id", userInfo.getId());
- userInfoMap.put("username", userInfo.getUsername());
- String token = JWTUtil.getToken(userInfoMap,secretKey);
- return ResultDTO.success(token);
- }
- return ResultDTO.error("密码错误");
- }
复制代码 配置拦截器拦截请求校验JWT令牌:
创建拦截器类实现HandlerInterceptor接口重写preHandle方法。通过@Value注解获取application.yml中配置的密钥,而后在preHandle方法中验证令牌的正确性,判断若在验证过程中报错则验证失败请求不放行并设置http相应状态码为401,若正确验证则放行请求。
注意:在拦截请求时放行用户登录接口和用户注册接口,放行请求代码在拦截器注册时配置。
- @Component
- public class LoginInterceptor implements HandlerInterceptor {
- @Value("${jwt.secret-key}")
- private String secretKey;
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- // 令牌验证
- String token = request.getHeader("Authorization");
- // 验证token
- try {
- JWTUtil.parseToken(token,secretKey);
- } catch (Exception e) {
- e.printStackTrace();
- // http响应状态码为401
- response.setStatus(401);
- // 不放行
- return false;
- }
- // 放行
- return true;
- }
- }
复制代码 拦截器注册到registry中:
获取刚刚创建的LoginInterceptor拦截器Bean对象,将拦截器注册到registry中,并设置注册和登录接口不拦截。
- @Configuration
- public class WebConfig implements WebMvcConfigurer {
- @Resource
- private LoginInterceptor loginInterceptor;
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- // registry: 注册器
- // 将拦截器注册到registry中, 注册和登录接口不拦截
- registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/register", "/user/login");
- }
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |