聊聊微服務認證之Oauth2
Oauth2是基于token的認證方式,它打通了web端和app端的統一認證,認證資料不需要存儲在服務端,用戶端隻需要攜帶token就可以實作認證
這裡說一下Oauth2的認證流程:
- 首先用戶端會向資源擁有者發起請求授權,例如微信
- 然後資源擁有者進行确認授權,例如輸入微信使用者名密碼後點選确認授權
- 這時用戶端收到授權許可之後就會向認證伺服器發起請求,申請令牌
- 認證伺服器收到請求之後生成token給用戶端
- 然後用戶端攜帶token資訊來通路資源伺服器,這裡比如擷取微信昵稱等等資訊
- 資源伺服器會先調用認證伺服器驗證token是否有效
- 資源伺服器将資源傳回給用戶端,也就是把微信資訊
一般情況下會有網關,用戶端會先請求網關,網關調用認證伺服器擷取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
搭建認證伺服器
- 繼承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接口的通路
-
繼承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請求: