SpringBoot2 整合OAuth2組件,模擬第三方授權訪問


本文源碼:GitHub·點這里 || GitEE·點這里

一、模式描述

授權服務

驗證第三方服務的身份,驗證郵箱用戶的身份,記錄和管理認證Token,為資源服務器提供Token校驗。場景:第三方網站借助用戶的郵箱登錄,並訪問郵箱賬戶的基礎信息,頭像、名稱等。

資源服務

第三方服務通過郵箱賬戶登錄后需要獲取的一些信息,即理解為資源,存儲郵箱賬戶的數據資源。

第三方服務

即借助郵箱用戶的賬戶,快速登錄第三個服務,免去繁雜的注冊流程,有助於快速積累新用戶。

交互流程

第三方服務給用戶開放快速郵箱登錄功能,引導用戶調到郵箱認證服務,通過認證后返回身份令牌到第三方服務,第三方服務攜帶令牌訪問郵箱的資源服務,獲取一些基本的郵箱用戶信息。

二、項目配置管理

1、案例結構

核心依賴

<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.1.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

這里有兩個核心組件依賴:OAuth2組件和Security組件。

模塊划分

  • auth-server:授權服務
  • resource-server:資源服務器
  • third-server:第三個服務

2、配置描述

【授權服務】

OAuth2配置

這里的配置管理的是第三方的授權流程和發放給第三方的身份證明ClientID和密碼,實際的場景就是第三方借助郵箱賬號登錄,首先就是向郵箱管理方提供材料,獲取訪問郵箱服務的身份證明,然后才能對接開放服務,這種模式在第三方對接業務中很常見。

/**
 * 模擬第三方授權配置
 */
@EnableAuthorizationServer
@Configuration
public class AuthConfig extends AuthorizationServerConfigurerAdapter {

    @Resource
    ClientDetailsService clientDetailsService;

    /**
     * 資源服務器校驗Token
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
    }
    /**
     * 第三方客戶端請求配置,和資源服務訪問的配置,不設置默認都可以訪問,提供默認回調地址
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("third01")
                .secret(new BCryptPasswordEncoder().encode("third01"))
                .resourceIds("resource-01")
                .authorizedGrantTypes("authorization_code","refresh_token")
                .scopes("all")
                .redirectUris("http://localhost:8082/notify.html");
    }
    /**
     * 配置訪問端點
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authorizationCodeServices(authorizationCodeServices()).tokenServices(tokenServices());
    }
    /**
     * 內存管理
     */
    @Bean
    AuthorizationCodeServices authorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }
    /**
     * Token管理規則
     */
    @Bean
    AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(clientDetailsService);
        services.setSupportRefreshToken(true);
        services.setTokenStore(tokenStore());
        services.setAccessTokenValiditySeconds(3600);
        services.setRefreshTokenValiditySeconds(3600*7);
        return services;
    }
    @Bean
    TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
}

通常需要數據庫存儲第三方信息,可以到第OAuth2開源項目中,獲取表結構放到本地數據庫中,然后這里換成數據源加載模式即可,簡單的流程管理都在源碼里寫了SQL語句,數據源引入即可。

Security配置

/**
 * 模擬本地用戶配置
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 密碼加密方式
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    /**
     * 內存中虛擬用戶和角色
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .roles("user");
    }
    /**
     * 表單登錄
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().formLogin();
    }
}

基於這里的配置管理郵箱用戶的認證流程,例如使用郵箱賬號密碼登錄驗證,判斷授權是否成立,這里管理的是服務本地的郵箱賬號,基於數據源存儲數據在下面案例中都有。

關於Spring框架中安全認證的相關的幾個組件,在使用OAuth2之前可以先了解一下。

【資源服務】

主要功能有三塊,配置第三方攜帶的Token身份令牌校驗機制,即訪問授權服務校驗接口,這里是OAuth2自定義好的接口;配置resourceId資源服務的編號,用來控制第三個服務能訪問的資源服務范圍,屬於大的權限點控制;模擬校驗用戶的Role角色,較精細的控制權限。

/**
 * 資源服務管理配置
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    /**
     * Token令牌校驗
     */
    @Bean
    RemoteTokenServices tokenServices() {
        RemoteTokenServices services = new RemoteTokenServices();
        services.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
        services.setClientId("third01");
        services.setClientSecret("third01");
        return services;
    }
    /**
     * 服務資源ID配置
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("resource-01").tokenServices(tokenServices());
    }
    /**
     * 模擬用戶權限規則
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated();
    }
}

【第三方服務】

主要提供兩個流程的模擬:請求授權服務獲取身份令牌;攜帶身份令牌請求資源服務獲取數據。這里則是授權碼回調接口的處理方式。

@Controller
public class NotifyController {

    private static final Logger LOG = LoggerFactory.getLogger(NotifyController.class);

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/notify.html")
    public String notify(String code, Model model) {
        if (code != null) {
            MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
            map.add("code", code);
            map.add("client_id", "third01");
            map.add("client_secret", "third01");
            map.add("redirect_uri", "http://localhost:8082/notify.html");
            map.add("grant_type", "authorization_code");
            Map<String,String> resp = restTemplate.postForObject("http://localhost:8080/oauth/token", map, Map.class);
            String accessToken = resp.get("access_token");
            LOG.info("身份令牌:{}",accessToken);
            HttpHeaders headers = new HttpHeaders();
            headers.add("Authorization", "Bearer " + accessToken);
            HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
            ResponseEntity<String> entity = restTemplate.exchange("http://localhost:8081/user/resource", HttpMethod.GET, httpEntity, String.class);
            model.addAttribute("notifyMsg", entity.getBody());
        }
        return "notify";
    }
}

三、測試流程

通過上述測試流程,對比常見的第三方登錄機制,理解OAuth2的授權碼模式。

四、源代碼地址

GitHub·地址
https://github.com/cicadasmile/middle-ware-parent
GitEE·地址
https://gitee.com/cicadasmile/middle-ware-parent

推薦閱讀:編程體系整理

序號 項目名稱 GitHub地址 GitEE地址 推薦指數
01 Java描述設計模式,算法,數據結構 GitHub·點這里 GitEE·點這里 ☆☆☆☆☆
02 Java基礎、並發、面向對象、Web開發 GitHub·點這里 GitEE·點這里 ☆☆☆☆
03 SpringCloud微服務基礎組件案例詳解 GitHub·點這里 GitEE·點這里 ☆☆☆
04 SpringCloud微服務架構實戰綜合案例 GitHub·點這里 GitEE·點這里 ☆☆☆☆☆
05 SpringBoot框架基礎應用入門到進階 GitHub·點這里 GitEE·點這里 ☆☆☆☆
06 SpringBoot框架整合開發常用中間件 GitHub·點這里 GitEE·點這里 ☆☆☆☆☆
07 數據管理、分布式、架構設計基礎案例 GitHub·點這里 GitEE·點這里 ☆☆☆☆☆
08 大數據系列、存儲、組件、計算等框架 GitHub·點這里 GitEE·點這里 ☆☆☆☆☆


免責聲明!

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



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