将用户角色映射到oauth2范围/权限

Sta*_*007 15 spring-security spring-security-oauth2

我们有一个权利数据库,其中包含应用程序ID,角色和用户映射到每个应用程序的角色.遵循线程建议如何基于resourceId将用户角色映射到oauth2范围/权限?

忽略我上面提到的权利数据库,我是否根据下面代码中的user和resourceId将角色"USER","READER","WRITER"映射到oauth2范围/权限?

用户认证/授权配置

@Configuration
@Order(-10)
protected static class LoginConfig extends WebSecurityConfigurerAdapter {

    ....

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // auth.parentAuthenticationManager(authenticationManager);
        // @formatter:off
        auth.inMemoryAuthentication()
            .withUser("admin").password("admin")
                .roles("ADMIN", "USER", "READER", "WRITER")
            .and()
            .withUser("user").password("password")
                .roles("USER")
            .and()
            .withUser("audit").password("audit")
                .roles("USER", "ADMIN", "READER");
        // @formatter:on
    }
}
Run Code Online (Sandbox Code Playgroud)

OAuth2配置

@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // @formatter:off
        clients.inMemory()
            .withClient("acme").secret("acmesecret")
                .authorizedGrantTypes("authorization_code", "refresh_token", "password")
                .scopes("openid")
            .and()
            .withClient("trusted").secret("shuush")
                .authorizedGrantTypes("client_credentials")
                .scopes("openid");
        // @formatter:on
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.checkTokenAccess("isAuthenticated()");
    }
}
Run Code Online (Sandbox Code Playgroud)

更新1:

在配置中引入了自定义OAuth2RequestFactory,将checkUserScopes设置为true.虽然此设置适用于"client_credentails",但它无法获得"代码"授权.对于"代码"授权,DefaultOAuth2RequestFactory尝试在授权步骤期间映射客户端(acme)的权限而不是用户.其他想法是实现ClientDetailsS​​ervice,它根据登录用户(admin/user)添加客户端(acme)的权限,但不确定如何从SecurityContext中获取登录用户,因为它在授权期间被客户端(acme)覆盖步.有任何想法吗?

public class ScopeMappingOAuth2RequestFactory extends DefaultOAuth2RequestFactory {

    private SecurityContextAccessor securityContextAccessor = new DefaultSecurityContextAccessor();

    public ScopeMappingOAuth2RequestFactory(ClientDetailsService clientDetailsService) {
        super(clientDetailsService);
        super.setCheckUserScopes(true);
    }

    /**
     * @param securityContextAccessor the security context accessor to set
     */
    @Override
    public void setSecurityContextAccessor(SecurityContextAccessor securityContextAccessor) {
        this.securityContextAccessor = securityContextAccessor;
        super.setSecurityContextAccessor(securityContextAccessor);
    }

    @Override
    public AuthorizationRequest createAuthorizationRequest(Map<String, String> authorizationParameters) {
        AuthorizationRequest request = super.createAuthorizationRequest(authorizationParameters);

        if (securityContextAccessor.isUser()) {
            request.setAuthorities(securityContextAccessor.getAuthorities());
        }

        return request;
    }

}
Run Code Online (Sandbox Code Playgroud)

并更新相关代码

@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    private InMemoryClientDetailsService clientDetailsService;

    private Map<String, ClientDetails> clientDetailsStore;

    public InMemoryClientDetailsService clientDetailsService() {
        if (clientDetailsService == null) {
            clientDetailsStore = new HashMap<String, ClientDetails>();
            InMemoryClientDetailsService m = new InMemoryClientDetailsService() {

                @Override
                public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
                    ClientDetails details = clientDetailsStore.get(clientId);
                    if (details == null) {
                        throw new NoSuchClientException("No client with requested id: " + clientId);
                    }
                    return details;
                }

            };
            clientDetailsService = m;
        }
        return clientDetailsService;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        InMemoryClientDetailsServiceBuilder builder = new InMemoryClientDetailsServiceBuilder() {

            @Override
            protected void addClient(String clientId, ClientDetails value) {
                clientDetailsStore.put(clientId, value);
            }

            @Override
            protected ClientDetailsService performBuild() {
                return clientDetailsService();
            }
        };
        clients.setBuilder(builder);

        // @formatter:off
        builder
            .withClient("acme").secret("acmesecret")
                .authorizedGrantTypes("authorization_code", "refresh_token", "password")
                .scopes("openid", "apim.read", "apim.write")
            .and()
            .withClient("trusted").secret("shuush")
                .authorizedGrantTypes("client_credentials")
                .scopes("openid", "apim.read", "apim.write")
                .authorities("openid", "apim.read", "apim.write");
        // @formatter:on
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.requestFactory(new ScopeMappingOAuth2RequestFactory(clientDetailsService()));
    }
Run Code Online (Sandbox Code Playgroud)

...}

LoginConfig

Configuration
@Order(-10)
protected static class LoginConfig extends WebSecurityConfigurerAdapter {

....

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // auth.parentAuthenticationManager(authenticationManager);
        // @formatter:off
        auth.inMemoryAuthentication()
            .withUser("admin").password("admin")
                .roles("APIM.READ", "APIM.WRITE")
            .and()
            .withUser("user").password("password")
                .roles("APIM.READ")
            .and()
            .withUser("audit").password("audit")
                .roles("APIM.READ");
        // @formatter:on
    }
}
Run Code Online (Sandbox Code Playgroud)

Seb*_*oek 0

我遇到了同样的问题,并且我还注意到代码运行了该checkUserScopes方法两次。我发现缺少的是用户和客户端都需要拥有您想要返回的权限。

因此,以这样的方式定义您的客户(根据您自己的角色调整角色):

    @Bean
    public ClientDetailsService clientDetailsService() {
        Map<String, ClientDetails> clientDetailsStore = new HashMap<>();

        Collection<String> scope = new HashSet<>();
        scope.add("user");
        scope.add("admin");

        Collection<GrantedAuthority> authorities = new HashSet<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

        Collection<String> authorizedGrantTypes = new HashSet<>();
        authorizedGrantTypes.add("authorization_code");

        BaseClientDetails clientDetails = new BaseClientDetails();
        clientDetails.setClientId("clientid");
        clientDetails.setClientSecret("{noop}secret"); //noop for Spring Security 5
        clientDetails.setScope(scope);
        clientDetails.setAuthorities(authorities);
        clientDetails.setAuthorizedGrantTypes(authorizedGrantTypes);

        clientDetailsStore.put("clientid", clientDetails);

        InMemoryClientDetailsService clientDetailsService = new InMemoryClientDetailsService();
        clientDetailsService.setClientDetailsStore(clientDetailsStore);

        return clientDetailsService;
    }
Run Code Online (Sandbox Code Playgroud)

现在客户端拥有所需的权限 user 和 admin。

并配置您的请求工厂:

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {

        DefaultOAuth2RequestFactory defaultOAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService());
        defaultOAuth2RequestFactory.setCheckUserScopes(true);
        endpoints.requestFactory(defaultOAuth2RequestFactory);
    }
Run Code Online (Sandbox Code Playgroud)