简体   繁体   English

spring boot oauth2 feign 允许匿名请求

[英]spring boot oauth2 feign allow anonymous requests

I have a client service that distribute a single page application.我有一个分发单页应用程序的客户端服务。 All the requests from the single page app pass through the client service that uses proxies (Feign) to redirect the calls.来自单页应用程序的所有请求都通过使用代理 (Feign) 重定向调用的客户端服务。

I'd like to allow anonymous calls but I'm not able to do that with my current configuration.我想允许匿名呼叫,但我目前的配置无法做到这一点。

So to make it simpler I have three services: a client, an oauth2 server and an oauth2 resource server.所以为了简单起见,我有三个服务:一个客户端、一个 oauth2 服务器和一个 oauth2 资源服务器。 The oauth2 server is also a resource server. oauth2 服务器也是一个资源服务器。

The client is connected to the oauth2-server with this configuration客户端使用此配置连接到 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

Here is the WebSecurityConfigurerAdapter class of the client, when an user try to access to the login path he's redirected to the oauth2-server to authenticate himself.这是客户端的 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);
}

The feign proxy used by the client, I'd like to configure the oauth2-server/user/like/*** path to be accessible by anonymous users.客户端使用的 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);
}

To transmit the token through Feign I have this configuration in the client Main class.要通过 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);
    }

}

Now the oauth2 server which also serves as a resource server现在 oauth2 服务器也用作资源服务器

@SpringBootApplication
@EnableResourceServer
@EnableAuthorizationServer
@EnableConfigurationProperties
public class AuthorizationServerApplication {}

the oauth2 server WebSecurityConfigurerAdapter class 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();
    }

}

The Rest controler method I'd like to allow to anonymous users我想允许匿名用户使用的 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);
    }
}

If I configure the Rest method with @PreAuthorize("hasRole('ROLE_ANONYMOUS')")如果我使用 @PreAuthorize("hasRole('ROLE_ANONYMOUS')") 配置 Rest 方法

and the WebSecurityConfigurerAdapter like this和这样的 WebSecurityConfigurerAdapter

  http.requestMatchers()
                .antMatchers(
                        ...
                        "/user/like/**",
                        ...)
                .and()
                .authorizeRequests()
                .antMatchers("/user/like/**")
                .anonymous()
                ...
        }
    } // @formatter:on

I'm able to get an answer if I contact directly the oauth2-server with Postman, but not if I pass through the client service that uses Feign, I'm always redirected to the login page.如果我使用 Postman 直接联系 oauth2-server,我能够得到答案,但如果我通过使用 Feign 的客户端服务,我总是被重定向到登录页面。

So how can I allow anonymous request Through Feign?那么如何通过 Feign 允许匿名请求呢?

I've found a solution but I'm not sure this is the Best way.我找到了解决方案,但我不确定这是最好的方法。 So if you have another solution you are welwome.因此,如果您有其他解决方案,您会很高兴。

So far I used this configuration to get the Token from the oauth2-server anytime an user made a request from the client through 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);
}

The problem with that configuration is that anytime I made a request with Feign a request is sent to the oauth2-client to the /oauth/authorize endpoint.该配置的问题在于,每当我向 Feign 发出请求时,都会将请求发送到 oauth2-client 到 /oauth/authorize 端点。 But if the user is not connected it fails, so an unauthenticated user cannot make any request from the client service.但是如果用户没有连接它就会失败,因此未经身份验证的用户无法从客户端服务发出任何请求。

So I used another RequestInterceptor.所以我使用了另一个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());

        }
    };
}

This way the token that the client service already has, once the user is connected, is added to the request whitout making another request to the /oauth/authorize endpoint.这样,一旦用户连接,客户端服务已经拥有的令牌被添加到请求中,而不会向 /oauth/authorize 端点发出另一个请求。 I think the token is sent with every request, I don't think it's a good practice for security matters.我认为令牌随每个请求一起发送,我认为这不是安全问题的好习惯。

Also in the WebSecurityConfigurerAdapter classes of the client-server I need to add the path so that it is accessible to non-connected users同样在客户端服务器的 WebSecurityConfigurerAdapter 类中,我需要添加路径,以便未连接的用户可以访问它

 http.antMatcher("/**")
            .authorizeRequests()
            .antMatchers(
                    "/oauth2-server/user/like/**",
                   ...)
            .permitAll()
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            ...;

same for the oauth2-server oauth2-server 也一样

 http.antMatcher("/**")
            .authorizeRequests()
            .antMatchers(
                    "/user/like/**",
                   ...)
            .permitAll()
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            ...;

With that configuration an unauthenticated user can make a request to an unprotected endpoint.使用该配置,未经身份验证的用户可以向未受保护的端点发出请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM