美文网首页
SpringBoot-JWT

SpringBoot-JWT

作者: 猫啸山林 | 来源:发表于2019-11-07 16:45 被阅读0次

    参考文章:https://www.jianshu.com/p/e88d3f8151db

    1、添加项目依赖

    implementation 'com.auth0:java-jwt:3.4.1'

    2、新建JWT工具类JwtUtil

    public class JwtUtil {
    
        // 过期时间120分钟
        public static final long EXPIRE_TIME = 120 * 60 * 1000;
    
        /**
         * 校验token是否正确
         *
         * @param token  密钥
         * @param secret 用户的密码
         * @return 是否正确
         */
        public static boolean verify(String token, String username, String secret) {
            try {
                // 根据密码生成JWT效验器
                Algorithm algorithm = Algorithm.HMAC256(secret);
                JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
                // 效验TOKEN
                DecodedJWT jwt = verifier.verify(token);
                return true;
            } catch (Exception exception) {
                return false;
            }
        }
    
        /**
         * 获得token中的信息无需secret解密也能获得
         *
         * @return token中包含的用户名
         */
        public static String getUsername(String token) {
            try {
                DecodedJWT jwt = JWT.decode(token);
                return jwt.getClaim("username").asString();
            } catch (JWTDecodeException e) {
                return null;
            }
        }
    
        /**
         * 生成签名,5min后过期
         *
         * @param username 用户名
         * @param secret   用户的密码
         * @return 加密的token
         */
        public static String sign(String username, String secret) {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
    
        }
    
    }
    

    3、编写Token验证拦截器

    public class AuthenticationInterceptor implements HandlerInterceptor {
    
        @Resource
        private UserRepository userRepository;
    
        @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 中的 user id
                    String username = JwtUtil.getUsername(token);
                    if (username == null) {
                        throw new RuntimeException("获取用户名失败,请重新登录");
                    }
                    SysUser user = userRepository.findByUsername(username);
                    if (user == null) {
                        throw new RuntimeException("用户不存在,请重新登录");
                    }
                    // 验证 token
                    return JwtUtil.verify(token, user.getUsername(), user.getPassword());
                }
    
            }
            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 {
    
        }
    
    }
    

    4、配置拦截器

    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
        }
    
        @Bean
        public AuthenticationInterceptor authenticationInterceptor() {
            return new AuthenticationInterceptor();
        }
    
    }
    

    5、全局异常捕捉

    @ControllerAdvice
    public class GloablExceptionHandler {
    
        @ResponseBody
        @ExceptionHandler(Exception.class)
        public Result<String> handleException(Exception e) {
            Result<String> result = new Result<>();
            String msg = e.getMessage();
            if (msg == null || msg.equals("")) {
                msg = "服务器出错";
            }
            result.error(msg);
            return result;
        }
    
    }
    

    6、自定义两个注解

    -跳过验证的PassToken

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

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

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

    7、用户登录UserController

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Resource
        private UserRepository userRepository;
    
        @RequestMapping(value = "/login", method = RequestMethod.POST)
        public Result<String> userLogin(@RequestBody LoginModel loginModel) {
            System.out.println(loginModel.getUsername() + "/" + loginModel.getPassword());
            Result<String> result = new Result<>();
            SysUser user = userRepository.findByUsername(loginModel.getUsername());
            if (user != null && loginModel.getPassword().equals(user.getPassword())) {
                user.setLoginTime(new Date());
                userRepository.saveAndFlush(user);
                String token = JwtUtil.sign(loginModel.getUsername(), loginModel.getPassword());
                System.out.println(token);
                result.setResult(token);
                result.success("登录成功");
            } else {
                result.error("用户名或密码错误");
            }
            return result;
        }
    
        @UserLoginToken
        @GetMapping("/getMessage")
        public String getMessage(){
            return "你已通过验证";
        }
    }
    

    相关文章

      网友评论

          本文标题:SpringBoot-JWT

          本文链接:https://www.haomeiwen.com/subject/fgmsbctx.html