天天看點

聊聊微服務認證之Oauth2

聊聊微服務認證之Oauth2

Oauth2是基于token的認證方式,它打通了web端和app端的統一認證,認證資料不需要存儲在服務端,用戶端隻需要攜帶token就可以實作認證

這裡說一下Oauth2的認證流程:

  1. 首先用戶端會向資源擁有者發起請求授權,例如微信
  2. 然後資源擁有者進行确認授權,例如輸入微信使用者名密碼後點選确認授權
  3. 這時用戶端收到授權許可之後就會向認證伺服器發起請求,申請令牌
  4. 認證伺服器收到請求之後生成token給用戶端
  5. 然後用戶端攜帶token資訊來通路資源伺服器,這裡比如擷取微信昵稱等等資訊
  6. 資源伺服器會先調用認證伺服器驗證token是否有效
  7. 資源伺服器将資源傳回給用戶端,也就是把微信資訊

一般情況下會有網關,用戶端會先請求網關,網關調用認證伺服器擷取token資訊,然後服務攜帶token資訊調用具體服務,服務擷取到token後調用認證伺服器校驗token有效性,如果有效就傳回資訊

把業務伺服器變成資源伺服器:

繼承ResourceServerConfigurerAdapter類,并使用@EnableResourceServer注解表示開啟資源服務的功能,重寫兩個configure()方法:

定義哪些方法需要放行不需要認證,哪些方法需要認證

public void configure(HttpSecurity httpSecurity) {
        httpSecurity.headers().frameOptions().disable();
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>
                .ExpressionInterceptUrlRegistry registry = httpSecurity
                .authorizeRequests();
        log.info(registry.toString() + "放行的url----->" + urls.toString());
        urls.forEach(url -> registry.antMatchers(url).permitAll());
        registry.anyRequest().authenticated()
                .and().csrf().disable();
    }
           

這裡是除了urls中的放行,其他都需要認證

定義資源伺服器向認證伺服器發起請求,進行token校驗

public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId("autodeliver");
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:9999/oauth/check_token");
        remoteTokenServices.setClientId("xiepanpan");
        remoteTokenServices.setClientSecret("123456");
        resources.tokenServices(remoteTokenServices);
    }
           

建立RemoteTokenServices,設定client secret 進行校驗token

搭建認證伺服器

  1. 繼承AuthorizationServerConfigurerAdapter類來定義認證伺服器配置類,類上添加@EnableAuthorizationServer注解,表示開啟認證伺服器,然後重寫三個configure()方法
public void configure(ClientDetailsServiceConfigurer clients) {
    TopeClientDetailsService clientDetailsService = new TopeClientDetailsService(dataSource);
    clients.withClientDetails(clientDetailsService);
  }
           

這個configure()是用來配置用戶端詳情的,包括client_id secret resourceid 認證類型、授權範圍等資訊,這裡是可以從資料庫中查詢用戶端詳情,TopeClientDetailsService繼承了JdbcClientDetailsService

@Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints
      .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
      .tokenStore(tokenStore())
      .tokenEnhancer(tokenEnhancer())
      .userDetailsService(userDetailsService)
      .authenticationManager(authenticationManager)
      .reuseRefreshTokens(false)
      .pathMapping("/oauth/confirm_access", "/token/confirm_access")
      .exceptionTranslator(new TopeWebResponseExceptionTranslator());
  }
           

這個configure()方法主要是對token的管理存儲,認證管理器、允許token校驗的請求方式

@Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
    oauthServer
      .allowFormAuthenticationForClients()
      .tokenKeyAccess("permitAll()")
      .checkTokenAccess("permitAll()");
  }
           

這個configure()方法是對安全點的限制,允許用戶端進行表單認證,運作生成token,允許驗證token接口的通路

  1. 繼承WebSecurityConfigurerAdapter類來定義認證相關的配置類

    重寫 configure(AuthenticationManagerBuilder auth)方法:

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        
        auth.userDetailsService(jdbcUserDetailsService).passwordEncoder(passwordEncoder);
    }
           

其中jdbcUserDetailsService是實作UserDetailsService接口的類的執行個體,并重寫loadUserByUsername()方法來驗證使用者名密碼

注冊認證管理器:

@Bean
  @Override
  @SneakyThrows
  public AuthenticationManager authenticationManagerBean() {
    return super.authenticationManagerBean();
  }
           

擷取token的url:

get請求:

http://localhost:8020/oauth/token?grant_type=password&client_id=client&client_secret=secret&username=xiepanpan&password=123456

校驗token,get請求:

http://localhost:8020/oauth/check_token?token=1232435323131

重新整理token,get請求:

總結