• SpringBoot集成JWT


    GitHub下载地址

                                                                                                                 JWT请求流程

    JWT验证登录的答题思路:

    1、用户输入用户名和密码,POST请求去登陆,验证无误后,JWT创建token返回给客户端。

    2、客户端将token存储在浏览器的cookie,前台发送请求要在Header携带token。

    3、后台使用拦截器,拦截有@UserLoginToken的方法,校验token

    4、服务器验证token正确后,返回数据给客户端。

    代码实现过程如下:

    封装JTW生成token和校验方法

    public class JwtTokenUtil {
    
        //公用密钥-保存在服务端,客户端是不会知道密钥的,以防被攻击
        public static String SECRET = "ThisIsASecret";
    
        //生成Troke
        public static String createToken(String username) {
            //签发时间
            //Date iatDate = new Date();
            //过地时间  1分钟后过期
            //Calendar nowTime = Calendar.getInstance();
            //nowTime.add(Calendar.MINUTE, 1);
            //Date expiresDate = nowTime.getTime();
            Map<String, Object> map = new HashMap();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            String token = JWT.create()
                        .withHeader(map)
                        //.withClaim( "name","Free码生") //设置 载荷 Payload
                        //.withClaim("age","12")
                        //.withClaim( "org","测试")
                        //.withExpiresAt(expiresDate)//设置过期时间,过期时间要大于签发时间
                        //.withIssuedAt(iatDate)//设置签发时间
                        .withAudience(username) //设置 载荷 签名的观众
                        .sign(Algorithm.HMAC256(SECRET));//加密
            System.out.println("后台生成token:" + token);
            return token;
        }
    
        //校验TOKEN
        public static boolean verifyToken(String token) throws UnsupportedEncodingException{
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            try {
                verifier.verify(token);
                return true;
            } catch (Exception e){
                return false;
            }
        }
    
        //获取Token信息
        public static DecodedJWT getTokenInfo(String token) throws UnsupportedEncodingException{
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            try{
                return verifier.verify(token);
            } catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    
    }
    View Code

     新建自定义注解:@UserLoginToken 

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UserLoginToken {
        boolean required() default true;
    }
    View Code

    使用拦截器拦截有@UserLoginToken注解的方法 

    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
        }
        @Bean
        public AuthenticationInterceptor authenticationInterceptor() {
            return new AuthenticationInterceptor();
        }
    }
    View Code
    public class AuthenticationInterceptor implements HandlerInterceptor {
        @Autowired
        UserService userService;
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
            // 如果不是映射到方法直接通过
            if(!(object instanceof HandlerMethod)){
                return true;
            }
            HandlerMethod handlerMethod=(HandlerMethod)object;
            Method method=handlerMethod.getMethod();
            //检查是否有passtoken注释,有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(UserLoginToken.class)) {
                UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
                if (userLoginToken.required()) {
                    // 执行认证
                    if (token == null) {
                        throw new RuntimeException("无token,请重新登录");
                    }
                    // 验证 token
                    if(JwtTokenUtil.verifyToken(token)){
                        return true;
                    }else {
                        throw new RuntimeException("401");
                    }
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    View Code

    登录:

    在Controller上登录方法不用添加@UserLoginToken自定义注解,其余获取后台数据方法加上@UserLoginToken自定义注解,目的验证token是否有效,是则返回数据,否则提示401无权限。

    测试:

    @Controller
    @RequestMapping(path = "/api")
    public class IndexController {
    
        private String prefix = "index/";
    
        @GetMapping("/index")
        public String index()
        {
            return prefix + "index";
        }
    
        @UserLoginToken
        @PostMapping("/test")
        @ResponseBody
        public Object test(){
            Map<String,Object> map = new HashMap<>();
            map.put("code","200");
            map.put("message","你已通过验证了");
            return map;
        }
    }
    View Code

    HTTP请求带上登陆成功后生成token,返回成功:

    HTTP请求带上无效token或不带token,返回失败:

  • 相关阅读:
    每天学习Linux——日志管理
    每天学习Linux——日志查看
    每天学习Linux命令——history
    .NET中property与attribute的区别,以及反射机制
    java内部类
    java的多态
    子类构造方法
    单例模式
    重载,重写
    数据库调优的方法有那些
  • 原文地址:https://www.cnblogs.com/zxg-6/p/12616561.html
Copyright © 2020-2023  润新知