【问题标题】:Keycloak custom SPI REST Endpoint with authorization具有授权的 Keycloak 自定义 SPI REST 端点
【发布时间】:2019-06-26 05:31:41
【问题描述】:

我正在尝试使用自定义 REST 端点制作自定义 SPI,它应该通过评估对请求资源的权限来验证和授权传入请求。 在调试器的帮助下,我发现我应该在我的 REST 处理程序方法中使用类 TokenEndpoint.java 并调用方法 permissionGrant(),但是当我尝试创建 TokenEndpoint 的实例时,我遇到了 REASTEASY 和 Keycloak 崩溃的错误。 你有任何例子,我该怎么做?

【问题讨论】:

    标签: keycloak keycloak-services


    【解决方案1】:

    【讨论】:

    • 感谢您的回复,但我需要在不使用 Keycloak 客户端的情况下修改 Keycloak 本身。我需要像此示例中的自定义 REST 端点 keycloak.org/docs/latest/server_development/… 。我可以对用户进行身份验证,甚至获得他的角色,但我还需要授权才能获得对资源的权限(客户端设置中的“授权”选项卡)。
    • @VyacheslavSamsonov 如果您能够解决该问题,我们将面临同样的问题,如果您可以与社区分享您的解决方案,这将非常有帮助,我们也在努力确保自定义休息端点..使用访问令牌
    • 此回复未回答问题。
    【解决方案2】:

    我建议看看以下项目:keycloak-avatar-minio-extension

    首先你必须实现一个 RealmResourceProdiverFactor 和一个 RealmResourceProdiver。

    其次,您需要一个在 RealmResourceProvider 中的 getResource() 被触发时返回的资源。

    您的资源是您在其中定义端点的类。 要检查授权,您可以创建如下方法:

    private AuthenticationManager.AuthResult resolveAuthentication(KeycloakSession session) {
        AppAuthManager appAuthManager = new AppAuthManager();
        RealmModel realm = session.getContext().getRealm();
    
        AuthenticationManager.AuthResult authResult = appAuthManager.authenticateIdentityCookie(session, realm);
        if (authResult != null) {
            return authResult;
        }
    
        return null;
    }
    

    此方法在构造函数中调用,并在您的资源中设置private final AuthenticationManager.AuthResult auth; 变量。

    现在在您的端点实现中,您可以简单地检查 auth 是否不为空,或者,如果需要,执行更复杂的操作,例如检查用户或您的 auth 变量中可用的令牌。

    【讨论】:

      【解决方案3】:

      我最近遇到了同样的问题。一般来说,瓦尔的回答是正确的。 为了让他的代码正常工作,我们必须添加对 keycloak-services 模块的依赖。您需要编译时依赖项(不要将 jar 添加到 ear 库中)和模块依赖项。 如何做到这一点的好例子是https://github.com/dteleguin/beercloak

      看点:

      1. https://github.com/dteleguin/beercloak/blob/master/beercloak-ear/src/main/application/META-INF/jboss-deployment-structure.xml
      2. https://github.com/dteleguin/beercloak/blob/master/beercloak-module/src/main/java/beercloak/resources/AbstractAdminResource.java - 设置方法
      3. https://github.com/dteleguin/beercloak/blob/master/beercloak-module/src/main/java/beercloak/providers/BeerResourceProvider.java - getResource 方法

      新版本认证在构造函数中不起作用,必须在getResource()方法中完成。

      【讨论】:

        【解决方案4】:

        和其他人一样,我需要在我们放入 keycloak 实例的自定义休息端点中使用它。

        我分步解决了这个问题:

        • 获取给定类型的资源
        • 获取这些资源的权限评估程序
        • 评估、过滤和返回响应

        代码如下:

        import java.util.Collection;
        import java.util.Collections;
        import java.util.HashSet;
        import java.util.Map;
        import java.util.Set;
        import java.util.stream.Collectors;
        
        import javax.ws.rs.GET;
        import javax.ws.rs.NotAuthorizedException;
        import javax.ws.rs.Path;
        import javax.ws.rs.Produces;
        import javax.ws.rs.core.MediaType;
        
        import org.keycloak.authorization.AuthorizationProvider;
        import org.keycloak.authorization.common.DefaultEvaluationContext;
        import org.keycloak.authorization.common.UserModelIdentity;
        import org.keycloak.authorization.model.Resource;
        import org.keycloak.authorization.model.ResourceServer;
        import org.keycloak.authorization.permission.ResourcePermission;
        import org.keycloak.authorization.permission.evaluator.Evaluators;
        import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
        import org.keycloak.models.ClientModel;
        import org.keycloak.models.KeycloakSession;
        import org.keycloak.models.RealmModel;
        import org.keycloak.representations.idm.authorization.AuthorizationRequest;
        import org.keycloak.representations.idm.authorization.Permission;
        import org.keycloak.services.managers.AppAuthManager;
        import org.keycloak.services.managers.AuthenticationManager.AuthResult;
        
        public class DemoResource {
            
            private final KeycloakSession session;
            private final AuthResult auth;
            
            public DemoResource(KeycloakSession session) {
                this.session = session;
                this.auth = new AppAuthManager.BearerTokenAuthenticator(session).authenticate();
            }
            
            @GET
            @Path("/demoresources")
            @Produces(MediaType.APPLICATION_JSON)
            public Set<Resource> listDemoResources() {
                if (this.auth == null || this.auth.getToken() == null) {
                    throw new NotAuthorizedException("Bearer");
                }
                
                String clientId = ""; // Client id which resources are defined.
                String resourceType = ""; // Get resources by type.
                
                final RealmModel realm = this.session.getContext().getRealm();
                final AuthorizationProvider authorizationProvider = this.session.getProvider(AuthorizationProvider.class);
                final ClientModel client = this.session.clientStorageManager().getClientByClientId(realm, clientId);
                final ResourceServer resourceServer = authorizationProvider
                    .getStoreFactory()
                    .getResourceServerStore()
                    .findById(client.getId());
                final Evaluators evaluators = authorizationProvider.evaluators();
                
                final AuthorizationRequest request = new AuthorizationRequest();
                request.setSubjectToken(this.auth.getToken().toString());
                
                // Get resources by type and put them in a map
                final Map<String, Resource> resourceMap = authorizationProvider
                    .getStoreFactory()
                    .getResourceStore()
                    .findByType(resourceType, resourceServer.getId())
                    .stream()
                    .collect(Collectors.toMap(Resource::getId, r -> r));
                
                // Generate a permission evaluator for all resources of given type
                final PermissionEvaluator permissionEvaluator = evaluators
                    .from(
                        resourceMap
                            .entrySet()
                            .stream()
                            .map(r -> new ResourcePermission(r.getValue(), Collections.emptyList(), resourceServer))
                            .collect(Collectors.toList()),
                        new DefaultEvaluationContext(new UserModelIdentity(realm, this.auth.getUser()), this.session));
                
                // Evaluate permission and put them in a result set.
                final Collection<Permission> permissions = permissionEvaluator.evaluate(resourceServer, request);
                final Set<Resource> resources = new HashSet<>();
                for (final Permission permission : permissions) {
                    if (resourceMap.containsKey(permission.getResourceId())) {
                        resources.add(resourceMap.get(permission.getResourceId()));
                    }
                }
                return resources;
            }
        }
        
        

        提供者

        import org.keycloak.models.KeycloakSession;
        import org.keycloak.services.resource.RealmResourceProvider;
        
        public class DemoProvider implements RealmResourceProvider {
            
            private KeycloakSession session;
            
            public DemoProvider(KeycloakSession session) {
                this.session = session;
            }
            
            @Override
            public void close() {
            }
            
            @Override
            public Object getResource() {
                return new DemoResource(this.session);
            }
        }
        

        提供者工厂

        import org.keycloak.Config.Scope;
        import org.keycloak.models.KeycloakSession;
        import org.keycloak.models.KeycloakSessionFactory;
        import org.keycloak.services.resource.RealmResourceProvider;
        import org.keycloak.services.resource.RealmResourceProviderFactory;
        
        public class DemoProviderFactory implements RealmResourceProviderFactory {
            
            public static final String ID = "demo";
            
            @Override
            public RealmResourceProvider create(KeycloakSession session) {
                return new DemoProvider(session);
            }
            
            @Override
            public void init(Scope config) {
            }
            
            @Override
            public void postInit(KeycloakSessionFactory factory) {
            }
            
            @Override
            public void close() {
            }
            
            @Override
            public String getId() {
                return ID;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2021-04-16
          • 2021-08-21
          • 1970-01-01
          • 2020-09-15
          • 2020-01-08
          • 1970-01-01
          • 2020-07-25
          • 1970-01-01
          • 2019-12-19
          相关资源
          最近更新 更多