You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为Keycloak授权服务器实现自定义分支策略及专属UI

为Keycloak 23.0.4自定义分支策略实现专属UI

一、完善后端SPI配置

你已经实现了基础的PolicyProvider和Representation,现在需要补充PolicyProviderFactory的配置,让Keycloak关联前端组件并处理策略参数:

  1. 添加策略配置属性
    重写getConfigProperties()方法,定义分支列表等配置项,让后端能接收前端传递的参数:

    @Override
    public List<ConfigProperty> getConfigProperties() {
        List<ConfigProperty> properties = new ArrayList<>();
        properties.add(new ConfigProperty(
            "allowedBranches",
            "Allowed Branches",
            "List of branches authorized to access the resource",
            ConfigProperty.MULTIVALUED_STRING_TYPE,
            null
        ));
        return properties;
    }
    
  2. 指定前端资源路径
    重写getFrontendPath()方法,指向你的前端组件文件:

    @Override
    public String getFrontendPath() {
        return "/js/custom-branch-policy.js";
    }
    
  3. 补充策略元数据
    重写以下方法,让UI显示正确的分类和名称:

    @Override
    public String getDisplayName() {
        return "Custom Branch Policy";
    }
    
    @Override
    public String getDescription() {
        return "Grants access based on user's branch affiliation";
    }
    
    @Override
    public String getPolicyType() {
        return "custom-branch";
    }
    
    @Override
    public String getGroup() {
        return "Custom"; // 若想和角色策略同组,可改为"Role"
    }
    
  4. 同步策略配置逻辑
    在createPolicy和updatePolicy中,将前端传递的配置映射到自定义Representation:

    @Override
    public Policy createPolicy(PolicyRepresentation representation, AuthorizationProvider authorization) {
        TosanBranchPolicyRepresentationExt branchRep = (TosanBranchPolicyRepresentationExt) representation;
        Policy policy = authorization.getStoreFactory().getPolicyStore().create(representation);
        policy.getConfig().put("allowedBranches", branchRep.getAllowedBranches());
        return policy;
    }
    
    @Override
    public void updatePolicy(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
        TosanBranchPolicyRepresentationExt branchRep = (TosanBranchPolicyRepresentationExt) representation;
        policy.getConfig().put("allowedBranches", branchRep.getAllowedBranches());
        authorization.getStoreFactory().getPolicyStore().update(policy);
    }
    

    同时确保TosanBranchPolicyRepresentationExt包含分支列表字段及getter/setter:

    public class TosanBranchPolicyRepresentationExt extends AbstractPolicyRepresentation {
        private List<String> allowedBranches;
    
        public List<String> getAllowedBranches() {
            return allowedBranches;
        }
    
        public void setAllowedBranches(List<String> allowedBranches) {
            this.allowedBranches = allowedBranches;
        }
    }
    

二、开发前端UI组件

Keycloak管理控制台基于React和AMD模块系统,需开发符合规范的前端组件实现分支选择交互:

  1. 创建前端组件文件
    在项目src/main/resources/META-INF/resources/keycloak/js/目录下创建custom-branch-policy.js,参考Keycloak内置策略组件结构实现:

    define([
        'react',
        'keycloak-ui/core',
        'keycloak-ui/components/policy-editor/common'
    ], function(React, Core, Common) {
        const { Form, FormGroup, MultiSelect } = Core;
        const { PolicyEditorBase } = Common;
    
        class CustomBranchPolicyEditor extends PolicyEditorBase {
            constructor(props) {
                super(props);
                this.state = {
                    allowedBranches: this.props.policy.config?.allowedBranches || []
                };
            }
    
            handleBranchChange = (value) => {
                this.setState({ allowedBranches: value });
                this.props.onChange({
                    ...this.props.policy,
                    config: {
                        ...this.props.policy.config,
                        allowedBranches: value
                    }
                });
            };
    
            render() {
                // 可替换为从后端接口动态获取的分支列表
                const branchOptions = [
                    { value: 'branch-shanghai', label: 'Shanghai Branch' },
                    { value: 'branch-beijing', label: 'Beijing Branch' },
                    { value: 'branch-guangzhou', label: 'Guangzhou Branch' }
                ];
    
                return (
                    <Form>
                        <FormGroup 
                            label="Allowed Branches" 
                            helpText="Select branches that can access the resource"
                        >
                            <MultiSelect
                                options={branchOptions}
                                value={this.state.allowedBranches}
                                onChange={this.handleBranchChange}
                                isMulti
                            />
                        </FormGroup>
                    </Form>
                );
            }
        }
    
        // 注册策略编辑器到Keycloak
        keycloak.provider.registerPolicyEditor({
            type: 'custom-branch', // 和后端getPolicyType()返回值一致
            group: 'Custom', // 和后端getGroup()返回值一致
            editor: CustomBranchPolicyEditor,
            displayName: 'Custom Branch Policy',
            description: 'Grants access based on user\'s branch affiliation'
        });
    
        return CustomBranchPolicyEditor;
    });
    
  2. 打包前端资源
    若使用ES6/React语法,需用Webpack或Rollup将代码打包为AMD模块,配置时将react、keycloak-ui等依赖外部化,避免重复打包。

三、部署与测试

  1. 打包部署
    将后端代码编译为jar包,确保前端资源custom-branch-policy.js位于jar包的META-INF/resources/keycloak/js/路径下,复制jar包到Keycloak的providers目录,执行kc.sh build(Windows用kc.bat build)后重启服务器。

  2. 验证UI与逻辑
    登录Keycloak管理控制台,进入授权标签页创建新策略,选择"Custom Branch Policy"即可看到自定义分支选择UI。同时需修改CustomBranchPolicyProvider的evaluate方法,从策略配置中读取allowedBranches来判断用户权限:

    @Override
    public void evaluate(Evaluation evaluation) {
        EvaluationContext context = evaluation.getContext();
        Identity identity = context.getIdentity();
        Attributes attributes = identity.getAttributes();
    
        String username = attributes.getValue("username").asString(0);
        Policy policy = evaluation.getPolicy();
        List<String> allowedBranches = policy.getConfig().getList("allowedBranches");
    
        if (allowedBranches != null && HasBranch(username, allowedBranches)) {
            evaluation.grant();
        } else {
            evaluation.deny();
        }
    }
    

内容的提问来源于stack exchange,提问作者Javad Malekzaseh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 04:27:33