【问题标题】:Mapping user roles to oauth2 scopes/authorities将用户角色映射到 oauth2 范围/权限
【发布时间】:2015-09-29 11:31:24
【问题描述】:

我们有一个权利数据库,其中包含应用程序 ID、角色和映射到每个应用程序角色的用户。遵循advice on thread 如何根据 resourceId 将用户角色映射到 oauth2 范围/权限?

忽略我上面提到的权利数据库,我是否在下面的代码中将角​​色“USER”、“READER”、“WRITER”映射到 基于用户和 resourceId 的 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
        }
    }

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()");
        }
    }

更新 1:

在配置中引入了自定义 OAuth2RequestFactory 以将 checkUserScopes 设置为 true。虽然此设置适用于“client_credentails”,但它无法用于“代码”授权。对于“代码”授权,DefaultOAuth2RequestFactory 在授权步骤中尝试为客户端(acme)而不是用户提供maps authorities。 其他想法是实现ClientDetailsService,它根据登录用户(管理员/用户)添加客户端(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;
        }
    
    }

并将相关代码更新为

    @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()));
        }
    
...
    }

登录配置

    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
        }
    }

【问题讨论】:

  • 任何指针@DaveSyer?
  • 我认为您必须评论他的其他答案之一才能让他看到您的消息。但即便如此,他可能也不会花时间回答你的问题。结果是谷歌搜索所有这些关键词只会导致一堆悬而未决的问题。最终的结果是人们没有实现 Spring OAuth2,因为 Spring on Stack Overflow 不支持它。

标签: spring-security spring-security-oauth2


【解决方案1】:

我遇到了同样的问题,我还注意到代码运行了两次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;
    }

现在客户端拥有所需的权限用户和管理员。

并配置您的请求工厂:

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {

        DefaultOAuth2RequestFactory defaultOAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService());
        defaultOAuth2RequestFactory.setCheckUserScopes(true);
        endpoints.requestFactory(defaultOAuth2RequestFactory);
    }

【讨论】:

    猜你喜欢
    • 2015-11-12
    • 2020-10-18
    • 2019-06-12
    • 2017-12-11
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    相关资源
    最近更新 更多