簡體   English   中英

spring boot oauth2 feign 允許匿名請求

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM