簡體   English   中英

使用 spring boot (security) 和 keycloak 啟用角色身份驗證?

[英]Enable role authentication with spring boot (security) and keycloak?

我正在嘗試做一件簡單的事情。

想要向單個端點發出請求並發送不記名令牌(來自客戶端),我希望此令牌得到驗證,並取決於在我的端點上的 keycloak 接受/拒絕請求上分配的角色。

我遵循了許多教程甚至書籍,但其中大部分我根本不明白。

按照此設置我的密鑰斗篷信息(領域、角色、用戶) https://medium.com/@bcarunmail/securing-rest-api-using-keycloak-and-spring-oauth2-6ddf3a1efcc2

所以,

我基本上用一個客戶端設置了我的密鑰斗篷,一個具有特定角色“用戶”的用戶,並像這樣配置它:

@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")

    }
}

我不明白為什么在許多教程中我看到這個(作為最后一條規則):

.anyRequest().permitAll();

基本上,當我設置為沒有安全性時,我可以在沒有承載令牌的情況下調用端點。

但是當我將其添加為最后一條規則時

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

我的問題?

我請求訪問令牌發送:

client_id -> my client from keycloak
username -> my user from keycloak
password -> my password from keycloak
grant_type -> password
client_secret -> from keycloak

我得到一個令牌,然后我用它來請求我的應用程序端點。 無論我使用什么端點(具有角色用戶或具有角色管理員的端點),我的請求始終有效。

在我的屬性中,我有這樣的事情:

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"
      ]
    }
  },

它是否以某種方式將 resource_access 與我的問題相關聯?

在調試堆棧中:我看到您正在調用/api/user/123並且在您的安全配置中您正在保護/user/*這不一樣,將您的安全更改為:

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

PS :你不需要注冊KeycloakAuthenticationProcessingFilterKeycloakPreAuthActionsFilter

允許所有:

每當您想允許任何請求訪問特定資源/URL 時,您都可以使用 permitAll。 例如,登錄 URL 應該可供所有人訪問。

拒絕全部:

無論何時您想阻止對特定 URL 的訪問,無論請求來自何處或是誰發出請求(管理員)

您還存在與 URL 和角色不匹配的情況(您將具有 admin 的 URL 授予 USER,反之亦然)。 (將角色用作 ROLE_ADMIN 或 ADMIN 或 USER 是一個好習慣)形成您的堆棧我可以看到未授予任何權限,因此請與權限重新檢查代碼

 http
         .csrf().disable()
         .authorizeRequests()
         .antMatchers("/api/user/**").hasRole("ADMIN")
         .antMatchers("/api/admin/**").hasRole("USER")
         .anyRequest().authenticated();
  1. 您是否嘗試不使用@Configuration 我認為您只需要在SecurityConf類上添加@KeycloakConfiguration注釋。

  2. 您的 antMatchers 是否尊重區分大小寫?

 http
    .csrf().disable()
    .authorizeRequests()
    .antMatchers("/api/user/**").hasRole("user")
    .antMatchers("/api/admin/**").hasRole("admin")
    .anyRequest().authenticated();
  1. 也請嘗試此配置,以刪除 Java 定義的 ROLE_* 約定:
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        // SimpleAuthorityMapper is used to remove the ROLE_* conventions defined by Java so
        // we can use only admin or user instead of ROLE_ADMIN and ROLE_USER
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }
  1. 如果你所有的端點都有相同的邏輯,安全配置就足夠了,你不需要其他注釋。 但是,如果您有另一個具有 admin 角色的端點,它不在您的“/api/admin”控制器中,您可以嘗試:
@PreAuthorize("hasRole('admin')")

我知道這是一篇舊帖子,但我只是寫這篇文章以備將來參考,以防其他人遇到同樣的問題。

如果您查看日志,Keycloak 成功驗證了訪問令牌,但沒有任何授予的權限。 這就是為什么 Spring 不授權請求並且您收到HTTP 403 Forbidden 的原因

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

這是因為 Keycloak 適配器被配置為使用資源(即客戶端級別)角色映射而不是領域級別角色映射:

use-resource-role-mappings :如果設置為 true,適配器將在令牌內部查找用戶的應用程序級角色映射。 如果為 false,它將查看用戶角色映射的領域級別。 這是可選的。 默認值為假。

是有關適配器配置的鏈接。

所以,如果你想通過領域角色獲得授權,屬性應該是這樣的:

keycloak:
  auth-server-url: http://localhost:8080/auth/
  resource: users-api
  credentials:
    secret : my-secret
  use-resource-role-mappings : false
  realm: my-realm
  realmKey:  my-key
  public-client: true
  principal-attribute: preferred_username
  bearer-only: true

注意:如果您想同時使用領域級別和客戶端級別的角色映射,那么您應該覆蓋 KeycloakAuthenticationProvider.authenticate() 方法以通過自己組合它們來提供必要的角色。

遲到的答案,但希望它能幫助其他面臨同樣問題的人。 我面臨着與您完全相同的問題,對我而言,在配置類中,我必須通過設置授予的權限映射器來更改默認的 keycloakAuthenticationProvider(@Override 方法僅用於調試):

@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
  KeycloakAuthenticationProvider keycloakAuthenticationProvider = new KeycloakAuthenticationProvider() {
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
      System.out.println("===========+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> authenticate ");
      KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication;
      for (String role : token.getAccount().getRoles()) {
        System.out.println("===========+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Role : " + role);
      }

      return super.authenticate(authentication);
    }
  };
  keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
  auth.authenticationProvider(keycloakAuthenticationProvider);
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM