在 Spring Boot 中使用 OAuth 2


什么是 OAuth 2

OAuth(開放授權)是一個開放標准,允許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密的資源(如照片,視頻,聯系人列表),而無需將用戶名和密碼提供給第三方應用。

OAuth 2.0 是 OAuth 協議的下一版本,但不向后兼容 OAuth 1.0。

OAuth 2.0 關注客戶端開發者的簡易性,同時為 Web 應用,桌面應用和手機,和起居室設備提供專門的認證流程。2012 年 10 月,OAuth 2.0 協議正式發布為 RFC 6749.

參考資源

1、理解OAuth 2.0 - 阮一峰的網絡日志

2、OAuth 2.0 教程

3、OAuth 2.0 官網

在 Spring Boot 中使用 OAuth 2

Spring Boot 中的 OAuth2 協議是在 Spring Security 的基礎上實現的。

令牌存儲在 Redis 中,redis 具有過期功能,很適合存儲令牌。

准備工作

所需依賴:

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

application.properties 配置文件:

# 使用 redis 存儲令牌
# redis 基本配置
spring.redis.host=146.56.200.244
spring.redis.password=Test@123456
spring.redis.port=6379
spring.redis.database=0

三大配置類

授權服務配置類:AuthorizationServerConfig

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    /**
     * 使用 password 登錄模式
     * 適用於前后端分離
     */
    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Autowired
    UserDetailsService userDetailsService;

    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                // 設置認證模式為 password
                .withClient("password")
                // 設置授權模式為 password 和 refresh_token
                // refresh_token 為 Spring Boot 中特有的授權模式
                .authorizedGrantTypes("password", "refresh_token")
                // token 的過期時間
                .accessTokenValiditySeconds(1800)
                // 設置資源 id,也就是資源的名字
                .resourceIds("rid")
                .scopes("all")
                .secret("$2a$10$3exePEMS2hwNVXzg3NRPVurMaA/ksEu5UGe6.cSctS3J7l6RsIarS");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory))
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
    }
}

資源服務配置類:ResourceServerConfig:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("rid").stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/admin/**").hasRole("user")
                .anyRequest().authenticated();
    }
}

Security 配置類:SecurityConfig

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        return super.userDetailsService();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("you").password("$2a$10$3exePEMS2hwNVXzg3NRPVurMaA/ksEu5UGe6.cSctS3J7l6RsIarS").roles("admin")
                .and()
                .withUser("fanqie").password("$2a$10$3exePEMS2hwNVXzg3NRPVurMaA/ksEu5UGe6.cSctS3J7l6RsIarS").roles("user");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/oauth/**")
                .authorizeRequests().antMatchers("/oauth/**").permitAll()
                .and().csrf().disable();
    }
}

控制類:HelloController

@RestController
public class HelloController {

    @GetMapping("/admin/hello")
    public String admin(){
        return "hello admin!";
    }

    @GetMapping("/user/hello")
    public String user(){
        return "hello user!";
    }

    @GetMapping("/hello")
    public String hello(){
        return "hello!";
    }

}

注,SecurityConfig 中的 password 和 AuthorizationServerConfig 中的 secret 是同一個密碼。

這個密碼是明文 123 通過 BCryptPasswordEncoder 加密后的效果,

在測試類中獲取加密后的密碼:

@SpringBootTest
class Oauth2ApplicationTests {

    @Test
    void contextLoads() {
        System.out.println(new BCryptPasswordEncoder().encode("123"));
    }
}

如下圖:

使用 postman 測試

如下圖

請求結果如下:

再將獲取到的 token 用於 get 請求,效果如下:

每天學習一點點,每天進步一點點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM