通过Keycloak保护Spring Boot中的个人资源

4

我有一个非常简单的Spring Boot应用程序,资源位于/repositories/persons

这是我的build.gradle文件。

plugins {
    id 'org.springframework.boot' version '2.4.0'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'
}

// use java 11 until keycloak is fixed
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencyManagement {
    imports {
        mavenBom "org.keycloak.bom:keycloak-adapter-bom:12.0.1"
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.keycloak:keycloak-spring-boot-starter'

    implementation 'org.flywaydb:flyway-core'
    runtime 'org.postgresql:postgresql'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

...
...

这是我的SecurityConfig.java文件。

@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) {
    var keycloakAuthenticationProvider = keycloakAuthenticationProvider();
    keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
    auth.authenticationProvider(keycloakAuthenticationProvider);
  }

  @Bean
  @Override
  protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
    return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
  }

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

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

这是我的 application.yaml 文件。

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/postgres
    username: john
    password: john

keycloak:
  auth-server-url: http://localhost:8081/auth/
  realm: myrealm
  resource: myclient
  credentials:
    secret: 45d43bd6-5ab9-476c-83c8-67bd203a78ee

所有内容都在我的本地机器上,Keycloak和Postgres是通过Docker Compose启动的。


version: "3.1"

volumes:
  postgres_data:
      driver: local

services:
  db:
    image: "postgres:13.1"
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: john
      POSTGRES_PASSWORD: john
  postgres:
    image: "postgres:13.1"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: password
  keycloak:
    image: quay.io/keycloak/keycloak:12.0.1
    environment:
      DB_VENDOR: POSTGRES
      DB_ADDR: postgres
      DB_DATABASE: keycloak
      DB_USER: keycloak
      DB_SCHEMA: public
      DB_PASSWORD: password
      KEYCLOAK_USER: admin
      KEYCLOAK_PASSWORD: Pa55w0rd
    ports:
      - 8081:8080
    depends_on:
      - postgres

我在Keycloak中有两个用户“zemirco”和“one”,他们都有“user”角色。它们都可以很好地工作,路由“/persons”受到保护,而“/repositories”对所有人开放。
这是我的问题!我想保护单个资源,例如“/person/1”。但我无法使其正常工作:( 我已经尝试了几天,但没有成功。这是我的Keycloak设置。
这是我的策略。

policy

这是资源。

resource

这里是权限。

permission

在Keycloak的评估过程中,一切都运作正常。然而,在我的Spring Boot应用程序中直接访问不起作用。尽管用户"one"应该只有访问权限,但我仍然可以使用"zemirco"访问"/person/1"。
我现在有点迷失方向。你有任何想法吗?
非常感谢!

编辑于2021年1月10日

感谢大家的回答,但我仍认为在我的应用程序方面不需要太多额外的努力就可以实现(这一点尤其适用于政策执行者https://www.keycloak.org/docs/latest/authorization_services/#_enforcer_overview)。

PEP负责强制执行访问决策,这些决策是通过评估与受保护资源相关联的策略来做出的。它充当过滤器或拦截器,以检查基于这些决策授予的权限是否可以实现对受保护资源的特定请求。

这听起来正是我想要做的事情。不幸的是,我无法使其工作。我只是认为我的配置是错误的或者可能不完整。我将为这个问题添加奖励。

3个回答

4

终于成功了 :) 我很开心!

这是我所做的。

首先,我使用了来自我的Keycloak客户端安装的keycloak.json文件。一开始我尝试将所有配置放入我的application.yaml中。必须将keycloak.json文件放置在src/main/webapp/WEB-INF/keycloak.json。当你使用JSON文件而不是YAML文件时,可以从你的SecurityConfig中删除以下内容。

public KeycloakConfigResolver keycloakConfigResolver() {
  return new KeycloakSpringBootConfigResolver();
}

这其实非常方便。你可以直接从Keycloak中复制粘贴内容到文件中,确保一切都是正确的。我看到的另一个问题是,在keycloak.json中的配置称为policy-enforcer,而在application.yaml中称为policy-enforcer-config。这相当烦人,因为我一开始没有意识到这点。以下是配置。

{
  "realm": "myrealm",
  "auth-server-url": "http://localhost:8081/auth/",
  "ssl-required": "external",
  "resource": "myclient",
  "verify-token-audience": true,
  "credentials": {
    "secret": "45d43bd6-5ab9-476c-83c8-67bd203a78ee"
  },
  "confidential-port": 0,
  "policy-enforcer": {}
}

"policy-enforcer": {}是最重要的部分。在这里,我们启用了默认设置,并简单地告诉Keycloak应该授权所有请求访问我们的资源。

然后一切似乎都正常工作了。只有使用正确的用户才能访问受保护的资源。但是,当我注销后再次尝试访问该资源时,我仍然能够访问它。在这里,我意识到我的ant匹配器设置不正确。以下是正确的配置。

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.authorizeRequests()
        .antMatchers("/persons/**") // changed from .antMatchers("/persons*")
        .hasRole("user")
        .anyRequest()
        .permitAll()
        .and()
        // this is just to have a convenient GET /logout method. DO NOT USE IN PRODUCTION
        .logout()
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
  }

现在一切都正常,我的Keycloak中的资源/策略/权限自动应用到了我的Spring Boot应用程序中。

我很高兴得知你能够仅依靠Keycloak安全性找到解决方案。虽然我仍认为Spring Security本身提供了更简单的方法来控制细粒度权限,但它确实很有趣。我会仔细审查它。+1 - jccampanero

1
Keycloak因其访问管理解决方案中最糟糕的策略/访问工具而闻名,然而,您所描述的问题似乎有些奇怪。
Keycloak是一种访问管理工具,在策略角度上提供决策,但不强制执行这些决策,因此只需要从Spring应用程序调用评估端点的api,如果返回200,则用户可以访问,否则页面将不会显示,因为策略评估按预期工作。
另一种选择是使用预先制作的策略执行点,apache/nginx spring都有他们自己的定制策略执行点。
一些有用的链接: 如何在Spring Boot应用程序中使用Keycloak策略执行器 keycloak-enforcement-filter

0

在Keycloak中进行授权很麻烦,我认为不应该使用它。有更好的解决方案(例如OPA)。只要遵循原则:“不做蠢事!"

其次,不要混淆AuthN和AuthZ。 仅仅因为在Keycloak中配置了一些AuthZ策略,并不意味着它们会被“自动和神奇地”使用。 如果您正在使用任何适配器(无论是Spring Security还是某些KC自己的适配器)进行身份验证,那么它们只是“OIDC”,而OIDC是关于AuthN,而不是AuthZ。

如果您想在应用程序中调整或使用您的AuthZ策略和规则,则必须单独查询它们以进行身份验证。 Keycloak提供了keycloak-authz-client,其中文档在此处:https://www.keycloak.org/docs/latest/authorization_services/#_service_client_api


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接