[学习笔记] SpringSecurity之OAuth2授权模式

# 学习 # · 2021-10-25

认识SpringSecurity-OAuth2

1、SpringSecurity OAuth2架构:

(1)用户访问Service,在没有Token时OAuth2RestTemplate会报错,且被Oauth2ClientContextFilter捕获到报错信息,并重定向到认证服务器(Authorization Server)。

(2)认证服务器通过授权端点(Authorization Endpoint)进行授权,并通过AuthorizationServerTokenServices生成授权码code并返回给客户端。

(3)客户端拿到授权码去认证服务器通过令牌端点(Token Endpoint)调用AuthorizationServerTokenServices生成令牌token并返回给客户端。

(4)客户端拿到token去资源服务器访问资源,通过Oauth2AuthenticationManager调用ResourceServerTokenServices进行校验,校验通过可以获取资源。


SpringSecurity-OAuth2授权模式

1、创建SpringBoot项目,并导入相关依赖。

<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>
    <!-- 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、创建SpringSecurity配置类:

/**
 * @Package: com.duo.config
 * @Description: SpringSecurity配置类
 * @Author 多仔
 */
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()
            .disable()
            .authorizeRequests()
            .antMatchers("/oauth/**", "/login/**", "/logout/**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .permitAll();
    }

    /**
     * @Author: 多仔
     * @Description: 返回PasswordEncoder实例
     * @return org.springframework.security.crypto.password.PasswordEncoder
     **/
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

3、创建SpringSecurity自定义登录逻辑:

/**
 * @Package: com.duo.service
 * @Description: 自定义登录逻辑
 * @Author 多仔
 */
@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        String password = passwordEncoder.encode("123456");
        return new User("admin", password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

4、创建资源服务器Controller:

/**
 * @Package: com.duo.controller
 * @Description: 用户中心控制器
 * @Author 多仔
 */
@RestController
@RequestMapping(value = "/user")
public class UserController {
    @GetMapping("/getUserInfo")
    public Object getUserInfo(Authentication authentication) {
        return authentication.getPrincipal();
    }
}

5、授权服务器配置:

/**
 * @Package: com.duo.config
 * @Description: 授权服务器配置
 * @Author 多仔
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                // 配置client_id
                .withClient("client-demo")
                // 配置client_secret
                .secret(passwordEncoder.encode("abcd"))
                // 配置redirect_uri,用于授权成功后跳转
                .redirectUris("http://www.baidu.com")
                // 配置申请的权限范围
                .scopes("all")
                // 配置grant-type,表示授权类型
                .authorizedGrantTypes("authorization_code");
    }
}

6、资源服务器配置:

/**
 * @Package: com.duo.config
 * @Description: 资源服务器配置
 * @Author 多仔
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .requestMatchers()
                //配置需要保护的资源路径
                .antMatchers("/user/**");
    }
}

7、启动项目,访问授权链接,登录正确的账号,获取授权码code:

http://localhost:8080/oauth/authorize?response_type=code&client_id=client-demo&redirect_uri=http://www.baidu.com&scope=all

8、根据授权码获取令牌token(使用PostMan模拟发送POST请求):

9、根据获取到的令牌token访问资源服务器请求获取资源:


在Redis中存储Token

1、在项目中引入Redis依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、编写Redis配置类:

@Configuration
public class RedisConfig {
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public TokenStore redisTokenStore(){
        return new RedisTokenStore(redisConnectionFactory);
    }
}

3、在授权服务器配置中指定令牌的存储策略为Redis:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    @Qualifier("redisTokenStore")
    private TokenStore redisTokenStore;
    @Autowired
    private UserDetailServiceImpl userDetailService;

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

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

4、使用PostMan请求Token:

5、在Redis客户端中查看结果:

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

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

评论