spring-security 将用户角色Map到oauth2作用域/权限

iibxawm4  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(194)

我们有一个授权数据库,其中包含应用程序ID、角色和Map到每个应用程序的角色的用户。在advice on thread之后,我如何基于resourceId将用户角色Map到oauth2范围/权限?
忽略我上面提到的权限数据库,我是否在下面的代码中根据用户和资源ID将角色“USER”、“READER”、“WRITER”Map到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”,但对于“code”赠款则失败。对于“code”授权,DefaultOAuth2RequestFactory尝试Map客户端的权限(acme)而不是用户。另一个想法是实现ClientDetailsService,它添加客户端的权限(acme)基于登录用户(admin/user),但不确定如何从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
        }
    }
uinbv5nw

uinbv5nw1#

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

现在,客户端具有所需的权限user和admin。
并配置您的请求工厂:

@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {

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

相关问题