SpringBoot学习:接口鉴权JWT

JWT
全称Json Web Token,是为了在应用间传递声明的基于json的开放式标准,用于双方之间以json的形式传递安全信息,因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

JWT结构
jwt由三段信息构成,以.号隔开,连接在一起就构成了jwt字符串,如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
.eyJzdWIiOiIxIiwiaXNzIjoiaHMiLCJleHAiOjE1NjAzOTM3NzB9
.ooOZAXtruR_aWKbQofolC8TXaKU65I9nPubhBW3LRq4

如上.号隔开的三段信息,分别代表着头部,负载,签证

  • Header
    JWT的头部承载两部分信息:token类型和采用的加密算法

    { 
      "alg": "HS256",
       "typ": "JWT"
    } 
    
  • Payload
    iss: jwt签发者
    sub: 面向的用户(jwt所面向的用户)
    aud: 接收jwt的一方
    exp: 过期时间戳(jwt的过期时间,这个过期时间必须要大于签发时间)
    nbf: 定义在什么时间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

  • Signature
    这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

SpringBoot集成JWT

  • JwtUtils :

    
    import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
    import static org.apache.commons.lang3.math.NumberUtils.toInt;
    import static org.apache.commons.lang3.math.NumberUtils.toLong;
    
    /**
     * @author: hs
     * @Date: 2019/6/11 20:58
     * @Description:
     */
    @Data
    @Component
    @ConfigurationProperties(prefix = "api.jwt")
    public class JwtUtils {
    
        private static final long EXPIRE_TIME = 30 * 60;
    
        private static final String SECRET = "HYBI%&J)(UJJ&TG&";
    
        private Long expire;
    
        private String secret;
    
    
        /**
         * @return 加密的token
         */
        public String sign(UserInfo userInfo) {
            Date date = new Date(System.currentTimeMillis() + toLong(this.expire.toString(), EXPIRE_TIME) * 1000);
            Algorithm algorithm = Algorithm.HMAC256(defaultIfBlank(this.secret, SECRET));
            // 附带username信息
            return JWT.create()
                    .withSubject(userInfo.getId().toString())
                    .withIssuer(userInfo.getUsername())
                    .withExpiresAt(date)
                    .sign(algorithm);
        }
    
        /**
         * 校验token是否正确
         *
         * @param token 密钥
         * @return 是否正确
         */
        public Map<String, Claim> verify(String token, String username) {
            try {
                Algorithm algorithm = Algorithm.HMAC256(defaultIfBlank(this.secret, SECRET));
                JWTVerifier verifier = JWT.require(algorithm).withIssuer(username).build();
                DecodedJWT jwt = verifier.verify(token);
                return jwt.getClaims();
            } catch (Exception e) {
                throw AppointException.errorMessage("鉴权失败,无效的用户");
            }
        }
    
        /**
         * 获得token中的信息无需secret解密也能获得
         *
         * @return token中包含的用户名
         */
        public String getUsername(String token) {
            try {
                DecodedJWT jwt = JWT.decode(token);
                return jwt.getIssuer();
            } catch (JWTDecodeException e) {
                throw AppointException.errorMessage("无效的token,请重新登录");
            }
        }
    
        /**
         * 获得token中的信息无需secret解密也能获得
         *
         * @return token中包含的id
         */
        public Integer getUserId(String token) {
            try {
                DecodedJWT jwt = JWT.decode(token);
                return toInt(jwt.getSubject());
            } catch (JWTDecodeException e) {
                throw AppointException.errorMessage("无效的token,请重新登录");
            }
        }
    }
    
  • 登录认证拦截器

    @Component
    public class AuthenticationInterceptor implements HandlerInterceptor {
    
        private static final String TOKEN = "token";
    
        private final JwtUtils jwtUtils;
    
        @Autowired
        public AuthenticationInterceptor(JwtUtils jwtUtils) {
            this.jwtUtils = jwtUtils;
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
            // 从 http 请求头中取出 token
            String token = request.getHeader(TOKEN);
            if (StringUtils.isBlank(token)) {
                token = request.getParameter(TOKEN);
            }
    
            // 如果不是映射到方法直接通过
            if (!(handler instanceof HandlerMethod)) {
                return true;
            }
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
    
            //LoginSkip,有则跳过认证
            if (method.isAnnotationPresent(LoginSkip.class)) {
                LoginSkip loginSkip = method.getAnnotation(LoginSkip.class);
                if (loginSkip.required()) {
                    return true;
                }
            }
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(LoginAuth.class)) {
                LoginAuth userLogin = method.getAnnotation(LoginAuth.class);
                if (userLogin.required()) {
                    // 执行认证
                    if (StringUtils.isBlank(token)) {
                        throw new RuntimeException("无效token,请重新登录");
                    }
                    String username = jwtUtils.getUsername(token);
                    jwtUtils.verify(token, username);
                    return true;
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
        }
    }
    
  • 拦截器注册配置

    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
    
        private final AuthenticationInterceptor authenticationInterceptor;
    
        @Autowired
        public InterceptorConfig(AuthenticationInterceptor authenticationInterceptor) {
            this.authenticationInterceptor = authenticationInterceptor;
        }
    
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authenticationInterceptor).addPathPatterns("/**");
        }
    }
    
  • api接口

    @RestController
    @RequestMapping("/api")
    @Api(description = "登录")
    public class LoginController {
    
        private final LoginService loginService;
    
        private final JwtUtils jwtUtils;
    
        @Autowired
        public LoginController(LoginService loginService, JwtUtils jwtUtils) {
            this.loginService = loginService;
            this.jwtUtils = jwtUtils;
        }
    
    
        @PostMapping("/login")
        @ApiOperation(value = "login接口", notes = "jwt接口权限验证")
        public AbstractApiResult login(@RequestBody UserInfo userInfo) {
            UserInfo user = loginService.getUserInfo(userInfo.getUsername());
            if (user == null) {
                throw AppointException.errorMessage(100, "用户名不存在");
            }
            String token = jwtUtils.sign(user);
            return AbstractApiResult.success(token);
        }
    
        @LoginAuth
        @GetMapping("testToken")
        @ApiOperation(value = "token", notes = "token测试")
        public String getMessage(@RequestHeader String token) {
            return "success";
        }
    
    }
    
  • 测试
    访问接口

    curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \ 
       "id": 0, \ 
       "username": "hs", \ 
       "password": "string" \ 
     }' 'http://localhost:9999/api/login'
    

    在这里插入图片描述
    带着token令牌eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaXNzIjoiaHMiLCJleHAiOjE1NjAzOTM3NzB9.ooOZAXtruR_aWKbQofolC8TXaKU65I9nPubhBW3LRq4访问接口:

    curl -X GET --header 'Accept: text/plain' --header 'token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaXNzIjoiaHMiLCJleHAiOjE1NjAzOTM3NzB9.ooOZAXtruR_aWKbQofolC8TXaKU65I9nPubhBW3LRq4' 'http://localhost:9999/api/testToken'
    

    在这里插入图片描述

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个基于Spring框架的快速开发的工具,它简化了Spring应用程序的配置和部署。 Spring Security是一个用于身份验证和授权的强大框架,它提供了一种灵活的方式来保护应用程序的安全性。 JWT(JSON Web Token)是一种用于安全传输信息的开放标准,它使用JSON对象进行安全传输。它是一种无状态的鉴权方式,服务器不需要存储用户的状态信息。 在使用Spring Boot和Spring Security进行登录鉴权时,可以借助JWT来进行身份验证。 首先,需要配置Spring Security来处理用户的登录请求和验证。可以使用Spring Security提供的身份验证过滤器来进行用户名和密码的验证。验证成功后,可以生成一个JWT,并返回给客户端。 在客户端接收到JWT后,将其存储在本地(通常是在前端的Cookie或LocalStorage中)。在进行后续的请求时,需要将JWT作为请求的头部信息中的Authorization字段发送给服务器。 服务器在接收到请求时,会先验证JWT的合法性,验证通过后可以根据JWT中的信息来进行后续的鉴权操作。 可以在服务器端配置一个自定义的JWT过滤器,用于验证JWT的合法性,并根据JWT中的信息来进行鉴权操作。可以根据需要从JWT中解析出用户的角色和权限信息,并根据这些信息来进行接口的访问控制。 通过以上的配置,可以实现基于Spring Boot、Spring Security和JWT的登录鉴权机制。这样可以保证系统的安全性,同时也能提高开发效率和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值