您现在的位置是:首页 >学无止境 >项目中遇到的一些问题总结(九)—— Spring Security 集成JWT、OAuth2完整验证流程网站首页学无止境

项目中遇到的一些问题总结(九)—— Spring Security 集成JWT、OAuth2完整验证流程

路上阡陌 2024-06-18 12:01:02
简介项目中遇到的一些问题总结(九)—— Spring Security 集成JWT、OAuth2完整验证流程

JWT验证

JWT验证本质上是对签名部分进行解密,并使用密钥验证是否被篡改。具体来说,JWT包含三个部分:Header、Payload和Signature。其中,Header和Payload部分是明文的,Signature部分是由Header和Payload部分加上密钥生成的哈希值,是加密之后的结果。

在JWT验证过程中,需要使用密钥对Signature部分进行解密,然后将解密后的结果与Header和Payload部分生成的哈希值进行对比。如果两个哈希值一致,说明JWT没有被篡改,验证通过。如果不一致,则说明JWT被篡改,验证失败。

需要注意的是,JWT验证中的密钥需要保密,并只在发行方和使用方之间共享。只有知道正确密钥的人才能够对JWT进行验证。

SpringSecurity集成JWT的整个认证流程

Spring Security集成JWT的认证流程如下:

  1. 客户端发送请求到服务器

  2. 服务器根据客户端提供的用户名和密码进行认证,如果认证成功,则生成Authentication对象。如果有需要,服务器还可以生成并添加一些其他的Claim,例如用户的角色、权限等。

  3. 服务器将Authentication对象中保存的信息转换为JWT Token的Payload部分,使用JwtAccessTokenConverter对象进行转换,同时生成Header和Signature,组成一个完整的JWT Token,返回给客户端。

  4. 客户端收到服务器返回的JWT Token,并将其保存在本地,以备后续使用。通常,JWT Token会保存在客户端的Cookie或LocalStorage中。

  5. 客户端在后续的请求中携带JWT Token,作为身份验证凭证传递给服务器。

  6. 服务器在接收到客户端的请求时,首先检查请求中是否包含JWT Token。如果不包含,则拒绝该请求。如果包含,则使用JwtAccessTokenConverter对象解析JWT Token,验证Token的合法性,解析出其中携带的信息,并将其保存在SecurityContext中。

  7. 服务器使用SecurityContextHolder中保存的SecurityContext对象,对请求进行进一步验证和授权。如果请求通过身份认证和授权验证,则返回相应的数据;否则返回相应的错误信息。

需要注意的是,JWT的认证过程是无状态的。服务器不需要在本地保存任何用户信息,只需通过Token即可进行身份认证和授权验证。这种无状态的认证方式非常适合分布式系统中的用户认证和授权场景,可以降低系统的复杂度和开发难度。同时,由于服务器不需要保存任何用户信息,也能够有效防止用户信息泄露的风险。

OAuth2授权服务器会将Authentication对象中保存的信息转换为JWT TokenPayload部分,
并使用JwtAccessTokenConverter对象进行转换。同时生成HeaderSignature,组成一个完整的JWT Token,并返回给客户端。

在OAuth2授权服务器中,JwtAccessTokenConverter是一个用于生成 JWT 令牌的处理器。
它的作用就是将Authentication对象转换为JWT令牌的payload部分,并使用签名密钥对其进行签名,
最终生成一个完整的 JWT 令牌。具体的流程如下:

1. 授权服务器根据业务逻辑从数据库或其他存储中获取用户的认证信息和授权信息,然后生成一个 Authentication 对象。

2. 授权服务器将 Authentication 对象传给 JwtAccessTokenConverter 对象,调用 convertAccessToken 方法
将 Authentication 对象转换为 JWT 令牌的Payload部分。

3. JwtAccessTokenConverter 对象使用预设的JWT参数和SigningKey,以及Authentication中包含的用户身份信息,
生成JWT令牌的HeaderSignature4. 授权服务器将生成的 JWT 令牌返回给客户端,客户端接收到 JWT 令牌后,可以使用它来访问受保护的资源。

需要注意的是,JwtAccessTokenConverter 可以自定义实现,以覆盖默认的 JWT 令牌生成方式,例如使用自定义的加密算法、调整 JWT 参数等。

可以通过创建一个模拟的 Authentication 对象来生成 JWT 令牌,以下是一个简单的示例代码:

@SpringBootApplication
@RestController
@EnableAuthorizationServer
public class DemoApplication extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter();
        jwtConverter.setSigningKey("my-jwt-secret-key"); //设置SigningKey用于签名
        return jwtConverter;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @GetMapping("/generateToken")
    public String generateToken(@RequestParam("username") String username, @RequestParam("password") String password) {
        // 模拟生成 Authentication 对象
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        Authentication auth = new UsernamePasswordAuthenticationToken(username, password, grantedAuthorities);

        // 生成 JWT 令牌
        OAuth2AccessToken token = convertAccessToken(auth);
        return token.getValue();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("client")
                .secret("{noop}secret")
                .authorizedGrantTypes("password", "refresh_token")
                .scopes("read", "write")
                .accessTokenValiditySeconds(3600)
                .refreshTokenValiditySeconds(7200);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)
                .accessTokenConverter(jwtAccessTokenConverter());
    }
}

上述代码中,生成 JWT 令牌使用了 convertAccessToken 方法,该方法由 OAuth2 中的 JwtAccessTokenConverter 类提供,它接收一个 Authentication 对象并返回一个 OAuth2AccessToken 对象。 AuthorizationServerEndpointsConfigurer 配置了如何使用该方法生成令牌,它的 accessTokenConverter 方法将 JwtAccessTokenConverter 对象设置为 JWT 令牌转换器。

在模拟的 generateToken 代码中,使用UsernamePasswordAuthenticationToken 创建了一个模拟的 Authentication 对象,并且调用 convertAccessToken 方法,将该对象传递给 JwtAccessTokenConverter 进行转换。之后从OAuth2AccessToken 对象获得 JWT 令牌的值并返回给客户端。

Spring Security 集成JWT、OAuth2完整验证流程

Spring Security集成JWT和OAuth2的完整验证流程可以分为以下几步:

  1. 客户端向服务器发起授权请求,携带客户端id、客户端secret和授权类型等认证信息(对应OAuth2中的Client Credentials流程)。

  2. 服务器对客户端进行身份认证,并将生成的Access Token保存在JWT Token的Payload部分中,并使用JwtAccessTokenConverter对象进行转换,最终生成一个JWT Token,返回给客户端。

  3. 客户端使用Access Token向资源服务器请求资源。

  4. 资源服务器接收到请求,首先检查JWT Token的合法性,使用JwtAccessTokenConverter对象解析JWT Token,并验证Token的签名和有效期。如果Token不合法,则拒绝该请求。如果Token合法,则从Token的Payload中获取Access Token,并使用Access Token对资源进行鉴权处理。

  5. 当 Access Token 失效的时候,客户端可以使用 Refresh Token 让服务器颁发新的 Access Token。

  6. 客户端在发送请求时,需要在 Authorization 请求头中携带 Access Token,并添加到其中。

  7. 资源服务器对请求进行进一步的验证与鉴权处理,根据其权限与角色返回相应数据。

需要注意的是,OAuth2和JWT Token的集成需要进行一些特定的配置。比如,我们需要使用相应的JwtAccessTokenConverter、TokenStore、TokenEnhancer等配置,来将OAuth2生成的Access Token和Refresh Token转换为JWT Token,并将其保存到TokenStore中。另外,在资源服务器的配置中,我们还需要添加JwtTokenStore和JwtAccessTokenConverter的Bean对象,用于验证JWT Token的合法性并解析其中携带的信息。除此之外,我们还需要在SecurityConfig中配置相应的授权策略,例如哪些路径需要哪些角色或权限才能访问等。

服务器对客户端进行身份认证,并将生成的Access Token保存在JWT Token的Payload部分中,并使用JwtAccessTokenConverter对象进行转换,最终生成一个JWT Token,返回给客户端 这个认证是不是SpringSecurity的认证流程

是的,这个认证是Spring Security的认证流程,在这个步骤中,Spring Security会对客户端进行身份认证,并生成Access Token,将其保存在JWT Token的Payload部分中,最后通过JwtAccessTokenConverter对象进行转换,生成JWT Token并返回给客户端。这是通过Spring Security来保护和认证资源服务器的一种常见方式。

是通过AuthenticationManganer认证码

是的,Spring Security使用AuthenticationManager来完成身份认证的过程。在这个过程中,Spring Security会通过AuthenticationProvider来对用户进行身份验证,并返回相应的Authentication对象,该对象包含了认证成功后的用户认证信息,比如用户名、密码、角色等。同时,Access Token也会被添加到该Authentication对象的details属性中,以方便后续使用。最后,通过JwtAccessTokenConverter对Authentication对象进行转换,生成JWT Token并返回给客户端。

TokenEnhancerChain

TokenEnhancerChain 是 Spring Security OAuth2 中用于控制 JWT token 增强器链(Token Enhancer)的类。使用 Token Enhancer 可以给 JWT token 添加自定义信息,如用户权限、用户名等等,增强 token 的功能。

当生成 JWT token 时,Spring Security OAuth2 会根据配置的 enhancer 链进行增强。TokenEnhancerChain 就是用于维护 enhancer 链的。

TokenEnhancerChain 中包含了多个 TokenEnhancer 对象,TokenEnhancer 定义了增强 token 的方法 enhance。当执行 TokenEnhancerChainenhance 方法时,会依次调用 enhancer 链中所有 enhancer 的 enhance 方法。每个 enhancer 将会在当前的 token 基础上添加自定义信息,并返回新的 token。增强完成后,TokenEnhancerChain 会返回增强后的 token。

使用 TokenEnhancerChain 维护 enhancer 链,可以根据实际需求定制 JWT token 的内容,使 JWT token 携带更多定制化信息,增强 token 的功能。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。