![](/img/trans.png)
[英]How to use Spring Boot feign client for Oauth2 authentication?
[英]spring boot oauth2 feign allow anonymous requests
我有一個分發單頁應用程序的客戶端服務。 來自單頁應用程序的所有請求都通過使用代理 (Feign) 重定向調用的客戶端服務。
我想允許匿名呼叫,但我目前的配置無法做到這一點。
所以為了簡單起見,我有三個服務:一個客戶端、一個 oauth2 服務器和一個 oauth2 資源服務器。 oauth2 服務器也是一個資源服務器。
客戶端使用此配置連接到 oauth2-server
security:
oauth2:
client:
clientId: autorisation_code_client
clientSecret: *******
accessTokenUri: https://localhost:****/oauth2-server/oauth/token
userAuthorizationUri: https://localhost:****/oauth2-server/oauth/authorize
#tokenCheckUri: https://localhost:****/oauth2-server/oauth/check_token
resource:
userInfoUri: https://localhost:****/oauth2-server/me
這是客戶端的 WebSecurityConfigurerAdapter class,當用戶嘗試訪問登錄路徑時,他被重定向到 oauth2-server 以進行身份驗證。
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers(
"/",
"/index.html",
"/login**",
"/logout**",
//resources
"/assets/**",
"/static/**",
"/*.ico",
"/*.js",
"/*.json").permitAll()
.anyRequest()
.authenticated()
.and()
.csrf().csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class);
}
客戶端使用的 feign 代理,我想配置 oauth2-server/user/like/*** 路徑讓匿名用戶可以訪問。
@RestController
@FeignClient(name = "oauth2-server", url = "https://localhost:****")
public interface ProxyOauth2Server {
@GetMapping(value = "oauth2-server/user/like/{name}")
ResponseEntity<?> getUserLikeName(@PathVariable("name") String name);
}
要通過 Feign 傳輸令牌,我在客戶端 Main class 中有此配置。
@EnableConfigurationProperties
@SpringBootApplication
@EnableFeignClients("com.tutosharing.client.proxies")
public class ClientUiApplication {
@Autowired
private SecurityPropertiesConfig config;
@Bean
protected OAuth2ProtectedResourceDetails resource() {
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setAccessTokenUri(config.getAccessTokenUri());
resource.setUserAuthorizationUri(config.getUserAuthorizationUri());
resource.setClientId(config.getClientId());
resource.setClientSecret(config.getClientSecret());
return resource;
}
@Bean
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails resource) {
return new OAuth2FeignRequestInterceptor(oauth2ClientContext, resource);
}
}
現在 oauth2 服務器也用作資源服務器
@SpringBootApplication
@EnableResourceServer
@EnableAuthorizationServer
@EnableConfigurationProperties
public class AuthorizationServerApplication {}
oauth2 服務器 WebSecurityConfigurerAdapter class
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/",
"/login",
"/login.do",
"/oauth/authorize**")
.and()
.authorizeRequests()
.antMatchers(
"/",
"/login",
"/login.do")
.permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login.do")
.usernameParameter("*********")
.passwordParameter("*********")
.and()
.userDetailsService(userDetailsServiceBean())
.requiresChannel()
.anyRequest()
.requiresSecure();
}
}
我想允許匿名用戶使用的 Rest 控制器方法
@RestController
public class UserRControllerRest {
@GetMapping({"/user/like/{name}"})
@JsonView(View.SimpleUser.class)
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity getUserLikeName(@PathVariable String name) {
Set<AuthUser> users = this.userRepository.findByNameLike(name);
return new ResponseEntity(users, HttpStatus.OK);
}
}
如果我使用 @PreAuthorize("hasRole('ROLE_ANONYMOUS')") 配置 Rest 方法
和這樣的 WebSecurityConfigurerAdapter
http.requestMatchers()
.antMatchers(
...
"/user/like/**",
...)
.and()
.authorizeRequests()
.antMatchers("/user/like/**")
.anonymous()
...
}
} // @formatter:on
如果我使用 Postman 直接聯系 oauth2-server,我能夠得到答案,但如果我通過使用 Feign 的客戶端服務,我總是被重定向到登錄頁面。
那么如何通過 Feign 允許匿名請求呢?
我找到了解決方案,但我不確定這是最好的方法。 因此,如果您有其他解決方案,您會很高興。
到目前為止,只要用戶通過 Feign 從客戶端發出請求,我就使用此配置從 oauth2-server 獲取 Token。
@Bean
protected OAuth2ProtectedResourceDetails resource() {
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setAccessTokenUri(config.getAccessTokenUri());
resource.setUserAuthorizationUri(config.getUserAuthorizationUri());
resource.setClientId(config.getClientId());
resource.setClientSecret(config.getClientSecret());
return resource;
}
@Bean
public RequestInterceptor oauth2FeignRequestInterceptor(@Qualifier("oauth2ClientContext") OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails resource) {
return new OAuth2FeignRequestInterceptor(oauth2ClientContext, resource);
}
該配置的問題在於,每當我向 Feign 發出請求時,都會將請求發送到 oauth2-client 到 /oauth/authorize 端點。 但是如果用戶沒有連接它就會失敗,因此未經身份驗證的用戶無法從客戶端服務發出任何請求。
所以我使用了另一個RequestInterceptor。
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return requestTemplate -> {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (!principal.equals("anonymousUser")) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)
SecurityContextHolder.getContext().getAuthentication().getDetails();
requestTemplate.header("Authorization", "bearer " + details.getTokenValue());
}
};
}
這樣,一旦用戶連接,客戶端服務已經擁有的令牌被添加到請求中,而不會向 /oauth/authorize 端點發出另一個請求。 我認為令牌隨每個請求一起發送,我認為這不是安全問題的好習慣。
同樣在客戶端服務器的 WebSecurityConfigurerAdapter 類中,我需要添加路徑,以便未連接的用戶可以訪問它
http.antMatcher("/**")
.authorizeRequests()
.antMatchers(
"/oauth2-server/user/like/**",
...)
.permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
...;
oauth2-server 也一樣
http.antMatcher("/**")
.authorizeRequests()
.antMatchers(
"/user/like/**",
...)
.permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
...;
使用該配置,未經身份驗證的用戶可以向未受保護的端點發出請求。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.