• SpringBoot整合JWT实现登陆验证


    🧑‍🎓 个人主页:花棉袄

    📖 本章内容:【SpringBoot整合JWT实现登陆验证
    ✍🏻 版权: 本文由【花棉袄】原创💝在CSDN首发💝需要转载请联系博主

    在这里插入图片描述

    🌼 SpringBoot整合JWT实现登陆验证🌼

    📢💨如果文章对你有帮助【关注👍点赞❤️收藏⭐】

    🍖Jwt消息构成

    • 头部(header)
    • 载荷(payload)
    • 签证(signature)

    🌳 Jwt的头部承载两部分信息

    • 声明类型–这里是Jwt
    • 声明加密的算法–通常直接使用 HMAC SHA256

    🌳载荷就是存放有效信息的地方

    • 标准中注册的声明的数据
    iss: jwt签发者
    sub: jwt所面向的用户
    aud: 接收jwt的一方
    exp: jwt的过期时间,这个过期时间必须要大于签发时间
    nbf: 定义在什么时间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 自定义数据
    定义数据:存放我们想放在token中存放的key-value值
    
    • 1

    🌳 签证信息

    • base64加密后的header和base64加密后的payload连接组成的字符串
    • 然后通过header中声明的加密方式进行加盐secret组合加密
    • 然后就构成了Jwt的第三部分

    🎁整合JWT

    • 引入依赖
    <dependency>
    		<groupId>com.auth0groupId>
    		<artifactId>java-jwtartifactId>
    		<version>3.10.3version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 自定义注解:需要登录才能进行操作的注解LoginToken
    /**
     * @Author 天才小狐狸
     * @Data 2022/8/6 1:54
     * @Description 需要登录才能进行操作的注解LoginToken
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LoginToken {
        boolean required() default true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 自定义注解:用来跳过验证的PassToken
    /**
     * @Author 天才小狐狸
     * @Data 2022/8/6 1:57
     * @Description 用来跳过验证的PassToken
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PassToken {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • Token生成
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private String userID;
        private String userName;
        private String passWord;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @Service
    public class TokenService {
        //5分钟之后过期
        private static final long EXPIRE_TIME = 5 * 60 * 1000;
    
        public String getToken(User user) {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
    
            String token = JWT.create().withAudience(user.getUserID())// 将 user id 保存到 token 里面
                    .withExpiresAt(date)
                    .sign(Algorithm.HMAC256(user.getPassWord()));// 以 password 作为 token 的密钥
            return token;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    @Service
    public class UserService {
     
        public User getUser(String userid ,String username, String password){
            if ("admin".equals(username) && "admin".equals(password)){
                User user=new User();
                user.setUserID(userid);
                user.setUserName(username);
                user.setPassWord(password);
                return user;
            }
            else{
                return null;
            }
        }
     
        public User getUser(String userid){
            if ("admin".equals(userid)){
                User user=new User();
                user.setUserID("admin");
                user.setUserName("admin");
                user.setPassWord("admin");
                return user;
            }
            else{
                return null;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    @SpringBootTest
    class SpringbootApplicationTests {
        @Autowired
        private TokenService tokenService;
    
        @Test
        void getToken() {
            User user = new User();
            user.setUserID("1");
            user.setPassWord("123");
            String token = tokenService.getToken(user);
            System.out.println(token);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 拦截器拦截token
    /**
     * @Author 天才小狐狸
     * @Data 2022/8/6 2:14
     * @Description
     */
    public class JwtInterceptor implements HandlerInterceptor {
        @Autowired
        private UserService userService;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            // 从 http 请求头中取出 token
            String token = request.getHeader("token");
    
            // 如果不是映射到方法直接通过
            if (!(handler instanceof HandlerMethod)) {
                return true;
            }
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
    
            //检查是否有passtoken注释,有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(LoginToken.class)) {
                LoginToken loginToken = method.getAnnotation(LoginToken.class);
                if (loginToken.required()) {
                    // 执行认证
                    if (token == null) {
                        throw new RuntimeException("无token,请重新登录");
                    }
                    // 获取 token 中的 user id
                    String userId;
                    try {
                        userId = JWT.decode(token).getAudience().get(0);
                    } catch (JWTDecodeException j) {
                        throw new RuntimeException("401");
                    }
                    User user = userService.getUser(userId);
                    if (user == null) {
                        throw new RuntimeException("用户不存在,请重新登录");
                    }
                    // 验证 token
                    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassWord())).build();
                    try {
                        jwtVerifier.verify(token);
                    } catch (JWTVerificationException e) {
                        throw new RuntimeException("401");
                    }
                    return true;
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 设置拦截规则&&注册拦截器
    /**
     * @title: InterceptorConfig
     * @Author gjt
     * @Date: 2020-12-21
     * @Description:设置拦截规则&&注册拦截器
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(jwtInterceptor())
                    .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
        }
    
        @Bean
        public JwtInterceptor jwtInterceptor() {
            return new JwtInterceptor();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 创建Controller
    @RestController
    public class Login {
    
        @Autowired
        private UserService userService;
        @Autowired
        private TokenService tokenService;
    
        @PostMapping("/login")
        public Result login(String userid, String username, String password) {
            User user = userService.getUser(userid, username, password);
    
            if (user == null) {
                return Result.fail("message", "登录失败!");
            } else {
                String token = tokenService.getToken(user);
                return Result.ok(token, "登录成功");
            }
        }
    
        @LoginToken
        @PostMapping("/getMessage")
        public Result getMessage() {
            return Result.ok("您已通过验证");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    📢💨如果文章对你有帮助【关注👍点赞❤️收藏⭐】

  • 相关阅读:
    软件测试人员的7个等级,据说只有1%的人能做到级别7
    淘宝API接口
    异质信息网络表征学习综述
    线程停止与中断、线程间通信三种方式
    Bootstrap 标签
    关于stm32的复用和重映射问题
    HUDI(搭建详细记录附加jar)
    AOP进阶-连接点
    机器学习:十大算法快速回顾
    Gee引擎常用功能简介
  • 原文地址:https://blog.csdn.net/m0_46914264/article/details/126188391