[学习笔记] SpringSecurity之OAuth2整合JWT和SSO

# 学习 # · 2021-10-27

OAuth2整合JWT

1、整合JWT:

(1)创建JwtTokenStore配置文件:

@Configuration
public class JwtTokenStoreConfig {
    @Bean
    public TokenStore jwtTokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
        accessTokenConverter.setSigningKey("salt");
        return accessTokenConverter;
    }
}

(2)在授权服务器配置中指定令牌的存储策略为JWT:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore jwtTokenStore;
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(jwtTokenStore)
                .userDetailsService(userDetailService)
                .accessTokenConverter(jwtAccessTokenConverter);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // ...
    }
}

(3)使用PostMan请求Token:

2、扩展JWT中存储的内容:

(1)继承TokenEnhancer实现一个JWT内容增强器:

public class JwtTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        Map<String,Object> info = new HashMap<>();
        info.put("enhance","enhance info");
        ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(info);
        return accessToken;
    }
    
}

(2)修改JwtTokenStore配置文件,创建一个JwtTokenEnhancer实例:

@Bean
public JwtTokenEnhancer jwtTokenEnhancer() {
    return new JwtTokenEnhancer();
}

(3)在授权服务器配置中配置JWT内容增强器:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    // ...

    @Autowired
    private JwtTokenEnhancer jwtTokenEnhancer;

    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList<>();
        // 配置JWT的内容增强器
        delegates.add(jwtTokenEnhancer);
        delegates.add(jwtAccessTokenConverter);
        enhancerChain.setTokenEnhancers(delegates);

        endpoints.tokenStore(jwtTokenStore)
                .userDetailsService(userDetailService)
                .accessTokenConverter(jwtAccessTokenConverter)
                .tokenEnhancer(enhancerChain);
    }
}

3、解析JWT中的内容:

(1)在项目中导入相关依赖:

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

(2)修改用户中心控制器类,使用JJWT工具类来解析Authorization头中存储的JWT内容。

@RestController
@RequestMapping(value = "/user")
public class UserController {
    @GetMapping("/getUserInfo")
    public Object getUserInfo(Authentication authentication, HttpServletRequest request) {

        String header = request.getHeader("Authorization");
        String token = header.substring(header.indexOf("bearer") + 7);
        return Jwts.parser()
                .setSigningKey("salt".getBytes(StandardCharsets.UTF_8))
                .parseClaimsJws(token)
                .getBody();
    }
}

4、刷新令牌:

(1)修改认证服务器的配置,添加refresh_token的授权模式。

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
        // 配置client_id
        .withClient("client-demo")
        // 配置client_secret
        .secret(passwordEncoder.encode("abcd"))
        // 配置访问token的有效期
        .accessTokenValiditySeconds(3600)
        // 配置刷新token的有效期
        .refreshTokenValiditySeconds(864000)
        // 配置redirect_uri,用于授权成功后跳转
        .redirectUris("http://www.baidu.com")
        // 配置申请的权限范围
        .scopes("all")
        // 配置grant_type,表示授权类型
        .authorizedGrantTypes("authorization_code","refresh_token");
}

(2)使用PostMan测试获取令牌:

(3)使用PostMan测试刷新令牌:


OAuth2整合单点登录SSO

1、创建客户端项目,并导入相关依赖。

<properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>

<dependencies>
    <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    <!-- SpringSecurity OAuth2整合依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-security</artifactId>
    </dependency>
    <!-- SpringBoot依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2、修改配置文件application.properties:

# 项目端口
server.port=8081

# 防止Cookie冲突,冲突会导致登录验证不通过
server.servlet.session.cookie.name=OAUTH2-CLIENT-SESSIONID01

#授权服务器地址
oauth2-server-url: http://localhost:8080

#与授权服务器对应的配置
security.oauth2.client.client-id=client-demo
security.oauth2.client.client-secret=abcd

security.oauth2.client.user-authorization-uri=${oauth2-server-url}/oauth/authorize
security.oauth2.client.access-token-uri=${oauth2-server-url}/oauth/token
security.oauth2.resource.jwt.key-uri=${oauth2-server-url}/oauth/token_key

3、在客户端启动类上添加注解启动单点登录功能。

@SpringBootApplication
@EnableOAuth2Sso
public class Oauth2client01demoApplication {
    // ...
}

4、创建测试控制器用于获取当前登录的用户信息。

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/getCurrentUser")
    public Object getCurrentUser(Authentication authentication) {
        return authentication;
    }

}

5、修改授权服务器配置,修改绑定的跳转路径,并添加获取秘钥时的身份认证。

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
            // 单点登录时配置
            .redirectUris("http://localhost:8081/login")
            // 自动授权配置
            .autoApprove(true)
            // ...
}

@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
    // 获取密钥需要身份认证,使用单点登录时必须配置
    security.tokenKeyAccess("isAuthenticated()");
}

6、启动测试。

如无特殊说明,本博所有文章均为博主原创。

如若转载,请注明出处:一木林多 - https://www.l5v.cn/archives/331/

评论