spring security OAuth2.0之客戶端Client的實現
阿新 • • 發佈:2019-05-17
ner hub context uestc tap tde val pos ise
項目代碼:https://github.com/hankuikuide/microservice-spring-security-oauth2
網上多數的項目客戶端都是采用純js寫,或用postman發請求,和實際項目的應用還是有差距的,這裏也是采用spring boot的實現。 主要功能在於:
- 使用授權碼模式進行認證。
- 使用OAuth2RestTemplate發送請求給認證服務器和資源服務器,
- 結合Feign實現loadbalance.
先進行security的配置:
@Configuration @EnableOAuth2Sso public class UiSecurityConfig extendsWebSecurityConfigurerAdapter { @Autowired OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter; @Override public void configure(HttpSecurity http) throws Exception { http.antMatcher("/**") .authorizeRequests() .antMatchers("/", "/login**") .permitAll().anyRequest().authenticated() .and() .addFilterBefore(oauth2ClientAuthenticationProcessingFilter,BasicAuthenticationFilter.class) .csrf().disable(); } }
在BasicAuthenticationFilter之前添加了一個過濾器。
客戶端中最關鍵的代碼,如下:
核心功能是
1. 註冊OAuth2RestTemplate,
2.註冊處理redirect uri的filter.也就是上面說的過濾器。
3. 註冊check token服務
有了這個類,使用授權碼模式,就可以把登錄成功後的授權碼接收到,並自動發給認證服務器請求token,並在後續的請求中自動添加token了。
@Configuration public class Oauth2ClientConfig { private String redirectUri ="http://localhost:9001/login"; private String checkTokenUrl ="http://localhost:9002/auth/oauth/check_token"; @Bean public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) { OAuth2RestTemplate template = new OAuth2RestTemplate(details, context); AuthorizationCodeAccessTokenProvider authCodeProvider = new AuthorizationCodeAccessTokenProvider(); authCodeProvider.setStateMandatory(false); AccessTokenProviderChain provider = new AccessTokenProviderChain( Arrays.asList(authCodeProvider)); template.setAccessTokenProvider(provider); return template; } /** * 註冊處理redirect uri的filter * @param oauth2RestTemplate * @param tokenService * @return */ @Bean public OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter( OAuth2RestTemplate oauth2RestTemplate, RemoteTokenServices tokenService) { OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(redirectUri); filter.setRestTemplate(oauth2RestTemplate); filter.setTokenServices(tokenService); //設置回調成功的頁面 filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { this.setDefaultTargetUrl("/home"); super.onAuthenticationSuccess(request, response, authentication); } }); return filter; } /** * 註冊check token服務 * @param details * @return */ @Bean public RemoteTokenServices tokenService(OAuth2ProtectedResourceDetails details) { RemoteTokenServices tokenService = new RemoteTokenServices(); tokenService.setCheckTokenEndpointUrl(checkTokenUrl); tokenService.setClientId(details.getClientId()); tokenService.setClientSecret(details.getClientSecret()); return tokenService; } }
再有雖然我們這裏配置了OAuth2RestTemplate,但是通過為了實現loadbalance,通過我們會使用FeignClient,介紹一下如何將二者結合使用。
為了使用@EnableFeignClients
首先引入依賴管理:
<dependencyManagement> <dependencies> <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>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
啟用FeignClient
@SpringBootApplication @EnableFeignClients public class ClientApplication { @Bean public RequestContextListener requestContextListener() { return new RequestContextListener(); } public static void main(String[] args) { SpringApplication.run(ClientApplication.class, args); } }
重要的配置來了:配置請求攔截器,並註入OAuth2RestTemplate
@Configuration public class OAuth2FeignAutoConfiguration { @Bean public RequestInterceptor oauth2FeignRequestInterceptor( OAuth2RestTemplate oAuth2RestTemplate) { return new OAuth2FeignRequestInterceptor(oAuth2RestTemplate); } }
實現這個攔截器:代碼很簡單就是把OAuth2RestTemplate 的token取出來放在restTemplate的header上,
public class OAuth2FeignRequestInterceptor implements RequestInterceptor { private static final String AUTHORIZATION_HEADER = "Authorization"; private static final String BEARER_TOKEN_TYPE = "Bearer"; private final OAuth2RestTemplate oAuth2RestTemplate; public OAuth2FeignRequestInterceptor(OAuth2RestTemplate oAuth2RestTemplate) { this.oAuth2RestTemplate = oAuth2RestTemplate; } @Override public void apply(RequestTemplate template) { System.out.println("Constructing Header "+AUTHORIZATION_HEADER+" for Token " + BEARER_TOKEN_TYPE +":" +oAuth2RestTemplate.getAccessToken().toString()); template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, oAuth2RestTemplate.getAccessToken().toString())); } }
定義服務接口
@FeignClient(name = "resource-service", url = "http://localhost:9003/auth", fallback = ResourceServiceFallback.class ) public interface ResourceService { @RequestMapping(value = "/hello", method = RequestMethod.GET) String hello(); }
大功告成!
spring security OAuth2.0之客戶端Client的實現