Java 使用spring boot(安全)和KeyClope启用角色身份验证?

Java 使用spring boot(安全)和KeyClope启用角色身份验证?,java,spring,spring-boot,keycloak,Java,Spring,Spring Boot,Keycloak,我想做一件简单的事 要向单个端点发出请求并发送承载令牌(来自客户端),我希望验证此令牌,具体取决于在我的端点上的KeyClope accept/deny请求上分配的角色 我听了很多教程,甚至是书,但大部分我都不懂 按照此步骤设置我的密钥斗篷信息(领域、角色、用户) 所以 我基本上是用一个客户机,一个具有特定角色“user”的用户来设置我的keybeave,并将其配置为: @Configuration @KeycloakConfiguration //@ComponentScan(basePac

我想做一件简单的事

要向单个端点发出请求并发送承载令牌(来自客户端),我希望验证此令牌,具体取决于在我的端点上的KeyClope accept/deny请求上分配的角色

我听了很多教程,甚至是书,但大部分我都不懂

按照此步骤设置我的密钥斗篷信息(领域、角色、用户)

所以

我基本上是用一个客户机,一个具有特定角色“user”的用户来设置我的keybeave,并将其配置为:

@Configuration
@KeycloakConfiguration
//@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConf extends KeycloakWebSecurityConfigurerAdapter
{
    /**
     * Registers the KeycloakAuthenticationProvider with the authentication manager.
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    /**
     * Defines the session authentication strategy.
     */
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        super.configure(http);
        http
                .authorizeRequests()
                .antMatchers("/user/*").hasRole("admin")
                .antMatchers("/admin*").hasRole("user")

    }
}
keycloak:
  auth-server-url: http://localhost:8080/auth/
  resource: users-api
  credentials:
    secret : my-secret
  use-resource-role-mappings : true
  realm: my-realm
  realmKey:  my-key
  public-client: true
  principal-attribute: preferred_username
  bearer-only: true
我不明白为什么在很多教程中我会看到这一点(作为最后一条规则):

基本上,当我设置没有安全性时,我可以在没有承载令牌的情况下调用端点

但当我把它作为最后一条规则加入时

 .anyRequest().denyAll();
我总是得到403分

我发现了这个:

请求是为了处理身份验证

f.KeycloakAuthenticationProcessingFilter : Attempting Keycloak authentication
o.k.a.BearerTokenRequestAuthenticator    : Found [1] values in authorization header, selecting the first value for Bearer.
o.k.a.BearerTokenRequestAuthenticator    : Verifying access_token
o.k.a.BearerTokenRequestAuthenticator    : successful authorized
a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: [] 
o.k.adapters.RequestAuthenticator        : User 'testuser' invoking 'http://localhost:9090/api/user/123' on client 'users'
o.k.adapters.RequestAuthenticator        : Bearer AUTHENTICATED
f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
o.s.s.authentication.ProviderManager     : Authentication attempt using org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider
o.s.s.core.session.SessionRegistryImpl   : Registering session 5B871A0E2AF55B70DC8E3B7436D79333, for principal testuser
f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@355f68d6: Principal: testuser; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@5d7a32a9; Not granted any authorities
[nio-9090-exec-3] o.s.security.web.FilterChainProxy        : /api/user/123 at position 8 of 15 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
nio-9090-exec-3] o.s.s.w.s.DefaultSavedRequest            : pathInfo: both null (property equals)
[nio-9090-exec-3] o.s.s.w.s.DefaultSavedRequest            : queryString: both null (property equals)
好像我没有担当角色

我的依赖项:

        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-starter</artifactId>
            <version>6.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-security-adapter</artifactId>
            <version>6.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
我得到一个令牌,然后我使用它请求我的应用程序endoint无论我使用什么端点(具有角色用户或具有角色管理员的端点),我的请求始终有效。

在我的酒店,我有这样的东西:

@Configuration
@KeycloakConfiguration
//@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConf extends KeycloakWebSecurityConfigurerAdapter
{
    /**
     * Registers the KeycloakAuthenticationProvider with the authentication manager.
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    /**
     * Defines the session authentication strategy.
     */
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        super.configure(http);
        http
                .authorizeRequests()
                .antMatchers("/user/*").hasRole("admin")
                .antMatchers("/admin*").hasRole("user")

    }
}
keycloak:
  auth-server-url: http://localhost:8080/auth/
  resource: users-api
  credentials:
    secret : my-secret
  use-resource-role-mappings : true
  realm: my-realm
  realmKey:  my-key
  public-client: true
  principal-attribute: preferred_username
  bearer-only: true
你知道如何在这种情况下实际启用角色吗

我必须配置客户端才能使用JWT吗?有什么想法吗

我还在端点上添加了注释

@Secured("admin")
@PreAuthorize("hasAnyAuthority('admin')")
但他们似乎什么都不做

--编辑--

在修复了与资源匹配的url后,我仍然得到403

"realm_access": {
    "roles": [
      "offline_access",
      "admin",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },

这与我的问题是否与资源访问有关?

在调试堆栈中:我看到您正在调用
/api/user/123
,并且在您的安全配置中,您正在保护
/user/*
的安全性,这是不同的,请将您的安全性更改为:

.antMatchers("/api/user/*").hasRole("user")
                .antMatchers("/api/admin*").hasRole("admin")

p.S:您不需要注册
keydepearthenticationprocessingfilter
keydepearthoutationsffilter
许可安装:

每当您希望允许任何请求访问特定资源/URL时,都可以使用permitAll。例如,每个人都应该可以访问登录URL

denyAll:

无论何时您想要阻止对特定URL的访问,无论请求来自何处或请求者是谁(管理员)

您还缺少与URL和角色的匹配(您正在向用户授予带有admin的URL,反之亦然)。(使用角色作为角色\管理员或管理员或用户是一种很好的做法)从堆栈中我可以看到未授予任何权限,因此请使用权限重新检查代码

 http
         .csrf().disable()
         .authorizeRequests()
         .antMatchers("/api/user/**").hasRole("ADMIN")
         .antMatchers("/api/admin/**").hasRole("USER")
         .anyRequest().authenticated();
  • 您是否尝试不使用
    @配置
    ?我认为您只需要在
    SecurityConf
    类上添加
    @keydeposeconfiguration
    注释

  • 你的对手尊重区分大小写吗

  • 还请尝试此配置,以删除Java定义的角色约定:
  • @Autowired
    public void configureGlobal(AuthenticationManagerBuilder身份验证){
    keydapertificationprovider keydapertificationprovider=keydapertificationprovider();
    //SimpleAuthorityMapper用于删除Java so定义的角色约定
    //我们只能使用admin或user,而不能使用ROLE\u admin和ROLE\u user
    keydovetAuthenticationProvider.setGrantedAuthoritiesMapper(新的SimpleAuthorityMapper());
    auth.authenticationProvider(keydaperthenticationProvider);
    }
    
  • 如果所有端点都有相同的逻辑,那么安全配置就足够了,不需要其他注释。但是,如果您有另一个具有admin角色的端点,而该端点不在“/api/admin”控制器中,则可以尝试:
  • @预授权(“hasRole('admin'))
    
    迟交答案,但希望它能帮助其他面临同样问题的人。 我面临着与您完全相同的问题,对我来说,在配置类中,我必须通过设置授权映射器(@Override方法仅用于调试)来更改默认的KeyDopperAuthenticationProvider:

    }我知道这是一篇老文章,但我写这篇文章只是为了将来参考,以防其他人也有同样的问题

    如果查看日志,keydove成功验证了访问令牌,但没有任何授权。这就是为什么Spring不授权请求,而您得到了HTTP 403禁止:

    这是因为keydape适配器配置为使用资源(即客户端级别)角色映射,而不是领域级别的角色映射:

    使用资源角色映射:如果设置为true,适配器将在令牌内查找用户的应用程序级别角色映射。如果为false,它将在领域级别查看用户角色映射。这是可选的。默认值为false

    是关于适配器配置的链接

    因此,如果您希望通过领域角色获得授权,属性应如下所示:

    @Configuration
    @KeycloakConfiguration
    //@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
    public class SecurityConf extends KeycloakWebSecurityConfigurerAdapter
    {
        /**
         * Registers the KeycloakAuthenticationProvider with the authentication manager.
         */
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(keycloakAuthenticationProvider());
        }
    
        /**
         * Defines the session authentication strategy.
         */
        @Bean
        @Override
        protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
            return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
        }
    
        @Bean
        public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
            return new KeycloakSpringBootConfigResolver();
        }
    
        @Bean
        public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
                KeycloakAuthenticationProcessingFilter filter) {
            FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
            registrationBean.setEnabled(false);
            return registrationBean;
        }
    
        @Bean
        public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
                KeycloakPreAuthActionsFilter filter) {
            FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
            registrationBean.setEnabled(false);
            return registrationBean;
        }
    
    
        @Override
        protected void configure(HttpSecurity http) throws Exception
        {
            super.configure(http);
            http
                    .authorizeRequests()
                    .antMatchers("/user/*").hasRole("admin")
                    .antMatchers("/admin*").hasRole("user")
    
        }
    }
    
    keycloak:
      auth-server-url: http://localhost:8080/auth/
      resource: users-api
      credentials:
        secret : my-secret
      use-resource-role-mappings : true
      realm: my-realm
      realmKey:  my-key
      public-client: true
      principal-attribute: preferred_username
      bearer-only: true
    
    钥匙斗篷:
    验证服务器url:http://localhost:8080/auth/
    资源:用户api
    资格证书:
    秘密:我的秘密
    使用资源角色映射:false
    领域:我的领域
    雷姆基:我的钥匙
    公共客户:对
    主体属性:首选的\u用户名
    仅持票人:对
    

    注意:如果您想同时使用领域级和客户端级角色映射,那么您应该重写keydoveauthenticationprovider.authenticate()方法,通过自己组合它们来提供必要的角色。

    .antMatchers(“/user/*”).hasRole(“admin”).antMatchers(/admin*”).hasRole(“用户”)它们是反向的,不是吗?你说保留是什么意思?我的意思是
    .antMatchers(/user/*).hasRole(“user”)
    .antMatchers(/admin*).hasRole(“admin”)首先,你从你的令牌中得到角色了吗?[调试]你调试过你的安全性中有角色吗?如果是,则前缀有问题,如果不是,则Keycl有问题
    f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@355f68d6: Principal: testuser; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@5d7a32a9; Not granted any authorities