H__D  

  JWT官网: https://jwt.io/

  JWT(Java版)的github地址:https://github.com/jwtk/jjwt

什么是JWT

  JWT 介绍参考:【JWT】JSON Web Token

  Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

JWT请求流程

  
 
 
  • 1. 用户使用账号和面发出post请求;

  • 2. 服务器使用私钥创建一个jwt;

  • 3. 服务器返回这个jwt给浏览器;

  • 4. 浏览器将该jwt串在请求头中像服务器发送请求;

  • 5. 服务器验证该jwt;

  • 6. 返回响应的资源给浏览器。

JWT的主要应用场景

  身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录(SSO)中比较广泛的使用了该技术。 信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。

优点

  • 1.简洁(Compact): 可以通过URLPOST参数或者在HTTP header

    发送,因为数据量小,传输速度也很快

  • 2.自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库

  • 3.因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。

  • 4.不需要在服务端保存会话信息,特别适用于分布式微服务。

JWT的集成使用

  新建SpringBoot项目,引入JWT依赖,由于是基于Java,所以需要的是java-jwt
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.8.3</version>
</dependency>

自定义两个注解

  用来跳过验证的PassToken

1 @Target({ElementType.METHOD, ElementType.TYPE})
2 @Retention(RetentionPolicy.RUNTIME)
3 public @interface PassToken {
4     boolean required() default true;
5 }

   需要登录才能进行操作的注解UserLoginToken

1 @Target({ElementType.METHOD, ElementType.TYPE})
2 @Retention(RetentionPolicy.RUNTIME)
3 public @interface UserLoginToken {
4     boolean required() default true;
5 }

 简单自定义一个实体类User

 1 package com.test.springboot.jwt.entity;
 2 
 3 public class User {
 4     String Id;
 5     String username;
 6     String password;
 7 
 8     public User() {
 9     }
10 
11     public User(String id, String username, String password) {
12         Id = id;
13         this.username = username;
14         this.password = password;
15     }
16 
17     public String getId() {
18         return Id;
19     }
20 
21     public void setId(String id) {
22         Id = id;
23     }
24 
25     public String getUsername() {
26         return username;
27     }
28 
29     public void setUsername(String username) {
30         this.username = username;
31     }
32 
33     public String getPassword() {
34         return password;
35     }
36 
37     public void setPassword(String password) {
38         this.password = password;
39     }
40 
41     @Override
42     public String toString() {
43         return "User{" +
44                 "Id='" + Id + '\'' +
45                 ", username='" + username + '\'' +
46                 ", password='" + password + '\'' +
47                 '}';
48     }
49 }
View Code

需要写token的生成方法

 1     /**
 2      * token的生成方法
 3      */
 4     public String getToken(User user) {
 5         String token="";
 6                 // 创建JWT
 7         token= JWT.create()
 8                 // 设置听众信息,也可以这是其他信息,如:withSubject主题
 9                 .withAudience(user.getId())
10                 // 签名
11                 .sign(Algorithm.HMAC256(user.getPassword()));
12         return token;
13     }
  Algorithm.HMAC256():使用HS256生成token,密钥则是用户的密码,唯一密钥的话可以保存在服务端。
  withAudience()存入需要保存在token的信息,这里我把用户ID存入token

拦截器去获取token并验证token

 1 package com.test.springboot.jwt.interceptor;
 2 
 3 import com.auth0.jwt.JWT;
 4 import com.auth0.jwt.JWTVerifier;
 5 import com.auth0.jwt.algorithms.Algorithm;
 6 import com.auth0.jwt.exceptions.JWTDecodeException;
 7 import com.auth0.jwt.exceptions.JWTVerificationException;
 8 import com.test.springboot.jwt.annotation.PassToken;
 9 import com.test.springboot.jwt.annotation.UserLoginToken;
10 import com.test.springboot.jwt.entity.User;
11 import com.test.springboot.jwt.service.UserService;
12 import org.springframework.beans.factory.annotation.Autowired;
13 import org.springframework.web.method.HandlerMethod;
14 import org.springframework.web.servlet.HandlerInterceptor;
15 import org.springframework.web.servlet.ModelAndView;
16 
17 import javax.servlet.http.HttpServletRequest;
18 import javax.servlet.http.HttpServletResponse;
19 import java.lang.reflect.Method;
20 
21 public class AuthenticationInterceptor implements HandlerInterceptor {
22 
23     @Autowired
24     UserService userService;
25 
26     @Override
27     public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
28         String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
29         // 如果不是映射到方法直接通过
30         if (!(object instanceof HandlerMethod)) {
31             return true;
32         }
33         HandlerMethod handlerMethod = (HandlerMethod) object;
34         Method method = handlerMethod.getMethod();
35         //检查是否有passtoken注释,有则跳过认证
36         if (method.isAnnotationPresent(PassToken.class)) {
37             PassToken passToken = method.getAnnotation(PassToken.class);
38             if (passToken.required()) {
39                 return true;
40             }
41         }
42         //检查有没有需要用户权限的注解
43         if (method.isAnnotationPresent(UserLoginToken.class)) {
44             UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
45             if (userLoginToken.required()) {
46                 // 执行认证
47                 if (token == null) {
48                     throw new RuntimeException("无token,请重新登录");
49                 }
50                 // 获取 token 中的 user id
51                 String userId;
52                 try {
53                     // 从jwt中获取信息
54                     userId = JWT.decode(token).getAudience().get(0);
55                 } catch (JWTDecodeException j) {
56                     throw new RuntimeException("401");
57                 }
58                 User user = userService.findUserById(userId);
59                 if (user == null) {
60                     throw new RuntimeException("用户不存在,请重新登录");
61                 }
62                 // 验证 token
63                 JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
64                 try {
65                     jwtVerifier.verify(token);
66                 } catch (JWTVerificationException e) {
67                     throw new RuntimeException("401");
68                 }
69                 return true;
70             }
71         }
72         return true;
73     }
74 
75     @Override
76     public void postHandle(HttpServletRequest httpServletRequest,
77                            HttpServletResponse httpServletResponse,
78                            Object o, ModelAndView modelAndView) throws Exception {
79 
80     }
81 
82     @Override
83     public void afterCompletion(HttpServletRequest httpServletRequest,
84                                 HttpServletResponse httpServletResponse,
85                                 Object o, Exception e) throws Exception {
86     }
87 
88 }

配置拦截器

package com.test.springboot.jwt.config;

import com.test.springboot.jwt.interceptor.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");   
    }

    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}

 Controller

 1 @RestController
 2 @RequestMapping("/user")
 3 public class UserController {
 4 
 5     @Autowired
 6     UserService userService;
 7 
 8     // 登录
 9     @PostMapping("/login")
10     public Map<String, Object> login(@RequestBody User user) {
11         Map<String, Object> result = new HashMap<>();
12 
13         User user1 = userService.findOne(user.getUsername(), user.getPassword());
14         if (user1 != null) {
15             String token = getToken(user1);
16             result.put("token", token);
17             result.put("user", user1);
18             return result;
19         } else {
20             result.put("message", "登录失败");
21             return result;
22         }
23     }
24 
25     @UserLoginToken
26     @GetMapping("/getMessage")
27     public Map<String, Object> getMessage() {
28         Map<String, Object> result = new HashMap<>();
29         result.put("content", "你已通过验证");
30         return result;
31     }
32 
33     @PassToken
34     @GetMapping("/getPublicMessage")
35     public Map<String, Object> getPublicMessage() {
36         Map<String, Object> result = new HashMap<>();
37         result.put("content", "公共信息");
38         return result;
39     }
40 
41 
42     /**
43      * token的生成方法
44      */
45     public String getToken(User user) {
46         String token="";
47                 // 创建JWT
48         token= JWT.create()
49                 // 设置听众信息,也可以这是其他信息,如:withSubject主题
50                 .withAudience(user.getId())
51                 // 签名
52                 .sign(Algorithm.HMAC256(user.getPassword()));
53         return token;
54     }
55 }

Service

 1 package com.test.springboot.jwt.service;
 2 
 3 import com.test.springboot.jwt.entity.User;
 4 import org.springframework.stereotype.Service;
 5 
 6 import java.util.HashMap;
 7 import java.util.Map;
 8 import java.util.concurrent.ConcurrentHashMap;
 9 
10 @Service
11 public class UserService {
12 
13     private static Map<String, User> userMap = new ConcurrentHashMap<>();
14 
15     static {
16         userMap.put("1001", new User("1001", "小白", "123456"));
17         userMap.put("1002", new User("1002", "小黑", "123456"));
18         userMap.put("1003", new User("1003", "小黄", "123456"));
19     }
20 
21     public User findOne(String username, String password) {
22         for (Map.Entry<String, User> entry : userMap.entrySet()) {
23             User value = entry.getValue();
24             if (value.getUsername().equals(username)
25                     && value.getPassword().equals(password)) {
26                 return value;
27             }
28         }
29         return null;
30     }
31 
32     public User findUserById(String userId) {
33         return userMap.get(userId);
34     }
35 }

使用postman测试接口

  

  

posted on 2021-07-19 01:15  H__D  阅读(229)  评论(0编辑  收藏  举报