【问题标题】:OAuth2 SSO for multiple resource servers with spring boot and jHipster使用 Spring Boot 和 jHipster 的多个资源服务器的 OAuth2 SSO
【发布时间】:2015-05-05 20:07:52
【问题描述】:

所以,我有一个 oAuth2 应用程序,它是 jHipster 应用程序(使用 mongodb)。我想将 3 个资源应用程序连接到该应用程序,但它们都应该共享相同的用户群,这样用户应该只能登录一次。

有没有办法在 Spring Boot 中使用 jHipster 配置多个资源,这样它就不会是一个单独的客户端,在访问资源之前需要用户名和密码?

还有如何为每个资源服务器指定用户角色?

所有的app都是基于spring-boot的。

下图是我想要完成的简单视图。

所以 OAuth2 应用具有授权服务器配置:

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
        AuthorizationServerConfigurerAdapter implements EnvironmentAware {

    private static final String ENV_OAUTH = "authentication.oauth.";
    private static final String PROP_CLIENTID = "clientid";
    private static final String PROP_SECRET = "secret";
    private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";

    private RelaxedPropertyResolver propertyResolver;

    @Inject
    private OAuth2AccessTokenRepository oAuth2AccessTokenRepository;

    @Inject
    private OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;

    @Bean
    public TokenStore tokenStore() {
        return new MongoDBTokenStore(oAuth2AccessTokenRepository,
                oAuth2RefreshTokenRepository);
    }

    @Inject
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {

        endpoints.tokenStore(tokenStore()).authenticationManager(
                authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients)
            throws Exception {
        clients.inMemory()
                .withClient("app-auth")
                .scopes("read", "write")
                .authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
                .authorizedGrantTypes("password", "refresh_token")
                .secret(propertyResolver.getProperty(PROP_SECRET))
                .accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800))

                .and()

                .withClient("app-A")
                .scopes("read", "write")
                .authorities(AuthoritiesConstants.ADMIN,AuthoritiesConstants.USER)
                .authorizedGrantTypes("password", "refresh_token")
                .secret(propertyResolver.getProperty(PROP_SECRET))
                .accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800))

                .and()

                .withClient("app-A")
                .scopes("read", "write")
                .authorities(AuthoritiesConstants.ADMIN,AuthoritiesConstants.USER)
                .authorizedGrantTypes("password", "refresh_token")
                .secret(propertyResolver.getProperty(PROP_SECRET))
                .accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800))

                .and()

                .withClient("app-C")
                .scopes("read", "write")
                .authorities(AuthoritiesConstants.ADMIN,AuthoritiesConstants.USER)
                .authorizedGrantTypes("password", "refresh_token")
                .secret(propertyResolver.getProperty(PROP_SECRET))
                .accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800));


    }

    @Override
    public void setEnvironment(Environment environment) {
        this.propertyResolver = new RelaxedPropertyResolver(environment,
                ENV_OAUTH);
    }
}

OAuth2 应用也有资源服务器配置:

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends
        ResourceServerConfigurerAdapter {

@Inject
private Http401UnauthorizedEntryPoint authenticationEntryPoint;

@Inject
private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

@Override
public void configure(HttpSecurity http) throws Exception {
    http.exceptionHandling()
            .authenticationEntryPoint(authenticationEntryPoint)
            .and()
            .logout()
            .logoutUrl("/api/logout")
            .logoutSuccessHandler(ajaxLogoutSuccessHandler)
            .and()
            .csrf()
            .requireCsrfProtectionMatcher(
                    new AntPathRequestMatcher("/oauth/authorize"))
            .disable().headers().frameOptions().disable()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().authorizeRequests().antMatchers("/api/authenticate")
            .permitAll().antMatchers("/api/register").permitAll()
            .antMatchers("/api/logs/**")
            .hasAnyAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api/**").authenticated()
            .antMatchers("/metrics/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/health/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/trace/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/dump/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/shutdown/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/beans/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/configprops/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/info/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/autoconfig/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/env/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/trace/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api-docs/**")
            .hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/protected/**").authenticated();
        }
    }

以及 App A 上的资源服务器(B 和 C 几乎相同):

@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {

@Override
public void configure(HttpSecurity http) throws Exception {
    http.requestMatchers().antMatchers("/api/**")
            .and()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
            .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')");
}

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("app-A");
    }

}

【问题讨论】:

  • 我不知道您为什么会认为这很困难。你有没有尝试过,但没有成功?
  • 我试图在主应用程序上添加一个@EnableAuthorizationServer@EnableResourceServer,但是当我为其中一个应用程序请求一个令牌时,例如使用http://localhost:8080/oauth/tokenusername=user&password=user&grant_type=password&scope=read%20write&client_secret=mySecretOAuthSecret&client_id=app_A 的帖子我得到一个弹出窗口,这是 Spring Security 的默认设置,要求我在请求令牌之前登录
  • /token 端点是反向通道。您不应该从浏览器访问它。也许你可以更详细地解释一下你做了什么。
  • 我已经用示例代码更新了问题。
  • 看起来(大部分)都还可以。我不知道为什么您需要在资源服务器中注销或保护 /authorize,但我认为他们不会做任何事情。客户在哪里?你在做什么来获得令牌,什么对你不起作用?

标签: spring spring-security spring-boot jhipster spring-security-oauth2


【解决方案1】:

@EnableResourceServer 注解默认保护您的所有资源(如果同一应用程序中有授权服务器,则 AuthorizationEndpoint 显式忽略或公开的资源除外)。

如果你想在同一个应用程序中设置多个资源服务器,你可以这样做:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

import java.util.Collections;
import java.util.List;

@Configuration
public class ResourceServersConfig {

    @Bean
    protected ResourceServerConfiguration adminResources() {
        ResourceServerConfiguration resource = new ResourceServerConfiguration() {
            public void setConfigurers(List<ResourceServerConfigurer> configurers) {
                super.setConfigurers(configurers);
            }
        };
        resource.setConfigurers(Collections.<ResourceServerConfigurer>singletonList(new ResourceServerConfigurerAdapter() {
            @Override
            public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
                resources.resourceId("admin-resources");
            }

            @Override
            public void configure(HttpSecurity http) throws Exception {
                http.antMatcher("/rest/admin/**").authorizeRequests().anyRequest()
                        .access("#oauth2.hasScope('administration') and #oauth2.clientHasRole('admin')");
            }
        }));
        resource.setOrder(3);
        return resource;
    }

    @Bean
    protected ResourceServerConfiguration userResources() {
        ResourceServerConfiguration resource = new ResourceServerConfiguration() {
            public void setConfigurers(List<ResourceServerConfigurer> configurers) {
                super.setConfigurers(configurers);
            }
        };
        resource.setConfigurers(Collections.<ResourceServerConfigurer>singletonList(new ResourceServerConfigurerAdapter() {
            @Override
            public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
                resources.resourceId("user-resources");
            }

            @Override
            public void configure(HttpSecurity http) throws Exception {
                http.antMatcher("/rest/user/**").authorizeRequests().anyRequest()
                        .access("#oauth2.hasAnyScope('offer','order') and #oauth2.clientHasRole('user')");
            }
        }));
        resource.setOrder(4);
        return resource;
    }

}

请看Dave Syer's example

【讨论】:

    猜你喜欢
    • 2017-04-13
    • 2018-08-29
    • 2021-02-07
    • 2015-05-14
    • 2021-08-04
    • 2022-08-03
    • 2016-04-22
    • 2016-05-21
    • 2014-07-09
    相关资源
    最近更新 更多