SpringBoot整合JWT认证机制实现接口鉴权

时间:2022-07-22
本文章向大家介绍SpringBoot整合JWT认证机制实现接口鉴权,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

什么是JWT认证机制

Json Web Token(缩写JWT)是目前最流行的跨域认证解决方案

session登录的认证方案是看,用户从客户端传递用户名和密码登录信息,服务端认证后将信息储存在session中,将session_id放入cookie中,以后访问其他页面,服务器都会带着cookie,服务端会自动从cookie中获取session_id,在从session中获取认证信息。

JWT的解决方案是,将认证信息返回个客户端,储存在客户端,下次访问其他页面,需要从客户端传递认证信息回服务器端。

JWT结构

一个完整的Json Web Token将分为三个部分,header(头部)、payload (负载) 、signature (签名)。

头部 (header)

头部通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA。

例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

然后,此JSON被 Base64Url 编码以形成JWT的第一部分。

有效载荷(payload)

令牌的第二部分是有效负载(payload),其中包含声明(claims)。声明是有关实体(通常是用户)和其他数据的声明。比如:registered, public, and private claims.

一个Payload的例子可以是

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

然后,对有效负载进行Base64Url编码,以形成JSON Web令牌的第二部分。

签名 (signature)

要创建签名部分,您必须获取编码的标头,编码的有效载荷,机密,标头中指定的算法,并对其进行签名。

例如,如果要使用HMAC SHA256算法,则将通过以下方式创建签名:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

签名用于验证消息在整个验证过程中没有更改,并且如果使用私钥进行令牌的签名的,它还可以验证JWT的发件人是谁。

最后,一个完整的Token可以是下面这样

SpringBoot与JWT的整合

通过在SpringBoot中整合JWT,可以构建有认证机制的Restful Web服务,或者实现前后端分离开发中的状态认证(比如和Vue进行整合)。

导入相关Maven依赖

        <!-- JWT Dependency-->
        <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>

编写JWT的工具类

这里设置了每个Token的失效时间为1个小时以后,payload中存储了用户的uid和用户名等信息,tokenPassword为进行HMAC256签名的私钥,需要进行安全性的存储。

public class JwtUtil {
    private static final String tokenPassword = "your_secret_key";

    public static String getToken(User user) {
        Instant dateTime = LocalDateTime.now().plusHours(1).toInstant(OffsetDateTime.now().getOffset());
        Date expireTime = Date.from(dateTime);
        String token;
        token = JWT.create()
                .withClaim("uid", user.getId())
                .withClaim("username", user.getUsername())
                .withIssuedAt(new Date())
                .withExpiresAt(expireTime)
                .sign(Algorithm.HMAC256(tokenPassword));
        return token;
    }

    public static int verifyToken(String token) {
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(tokenPassword)).build();
        try {
            jwtVerifier.verify(token);
        } catch (TokenExpiredException e) {
            return Status.WARNING;
        } catch (JWTVerificationException e) {
            return Status.FORBIDDEN;
        }
        return Status.SUCCESS;
    }
}

构建继承HandlerInterceptor的SpringBoot拦截器

@Component
public class UserInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("Authorization").substring(7);
        int result = JwtUtil.verifyToken(token);
        if (result == Status.FORBIDDEN) {
            response.setStatus(401);
            return false;
        } else if (result == Status.WARNING) {
            request.setAttribute("tokenExpired", true);
        }
        request.setAttribute("tokenExpired", false);
        return true;
    }
}

构建WebConfigurer类来注入拦截器

@Configuration
public class WebConfigurer implements WebMvcConfigurer {

    UserInterceptor userInterceptor;

    public WebConfigurer(UserInterceptor userInterceptor) {
        this.userInterceptor = userInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(userInterceptor).addPathPatterns("/api/user/**");
    }
   // 解决浏览器端跨站安全机制的问题
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .allowedHeaders("Authorization");
    }
}

经过上述的操作,在对匹配的路径进行请求后,拦截器将会验证HTTP Headers中的Authorization头中的Token,并进行对应的传递或响应。

提示

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:

https://cloud.tencent.com/developer/support-plan?invite_code=1v5xqqcp1en4i