fix: sso optimization (#1159)
* fix: update submodules * fix: improve code
This commit is contained in:
		
							parent
							
								
									37b4151da1
								
							
						
					
					
						commit
						205fafcd4a
					
				@ -1,9 +1,9 @@
 | 
			
		||||
import React, { useEffect, useState, useRef } from 'react';
 | 
			
		||||
import { Button, Space } from 'antd';
 | 
			
		||||
import { LoginOutlined } from '@ant-design/icons';
 | 
			
		||||
import { useMemoizedFn } from 'ahooks';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { useAPIClient, useRedirect } from '@nocobase/client';
 | 
			
		||||
import { useAPIClient, useRedirect, useRequest } from '@nocobase/client';
 | 
			
		||||
import { useMemoizedFn } from 'ahooks';
 | 
			
		||||
import { Button, Space } from 'antd';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
 | 
			
		||||
export interface OIDCProvider {
 | 
			
		||||
  clientId: string;
 | 
			
		||||
@ -12,26 +12,14 @@ export interface OIDCProvider {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const OIDCList = () => {
 | 
			
		||||
  const [list, setList] = useState<OIDCProvider[]>([]);
 | 
			
		||||
  const [windowHandler, setWindowHandler] = useState<Window | undefined>();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const redirect = useRedirect();
 | 
			
		||||
 | 
			
		||||
  const getOidcList = async () => {
 | 
			
		||||
    const { data: pluginsRes } = await api.request({
 | 
			
		||||
      url: 'app:getPlugins',
 | 
			
		||||
    });
 | 
			
		||||
    if (!(pluginsRes.data as string[]).includes('oidc')) return;
 | 
			
		||||
    const { data: providersRes } = await api.request({
 | 
			
		||||
      url: 'oidcProviders:list',
 | 
			
		||||
      params: {
 | 
			
		||||
        filter: {
 | 
			
		||||
          enabled: true,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    setList(providersRes.data);
 | 
			
		||||
  };
 | 
			
		||||
  const { data, loading } = useRequest({
 | 
			
		||||
    resource: 'oidc',
 | 
			
		||||
    action: 'getEnabledProviders',
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 打开登录弹出框
 | 
			
		||||
@ -80,10 +68,6 @@ export const OIDCList = () => {
 | 
			
		||||
    };
 | 
			
		||||
  }, [windowHandler]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    getOidcList();
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Space
 | 
			
		||||
      direction="vertical"
 | 
			
		||||
@ -91,9 +75,9 @@ export const OIDCList = () => {
 | 
			
		||||
        display: flex;
 | 
			
		||||
      `}
 | 
			
		||||
    >
 | 
			
		||||
      {list.map((item) => (
 | 
			
		||||
      {data?.data?.map?.((item) => (
 | 
			
		||||
        <Button shape="round" block key={item.clientId} icon={<LoginOutlined />} onClick={() => handleOpen(item)}>
 | 
			
		||||
          OIDC: {item.title}
 | 
			
		||||
          {item.buttonTitle}
 | 
			
		||||
        </Button>
 | 
			
		||||
      ))}
 | 
			
		||||
    </Space>
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,13 @@
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { i18n } from '@nocobase/client';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
 | 
			
		||||
import zhCN from './zh-CN';
 | 
			
		||||
import enUS from './en-US';
 | 
			
		||||
import jaJP from './ja-JP';
 | 
			
		||||
import ruRU from './ru-RU';
 | 
			
		||||
import trTR from './tr-TR';
 | 
			
		||||
import zhCN from './zh-CN';
 | 
			
		||||
 | 
			
		||||
export const NAMESPACE = 'workflow';
 | 
			
		||||
export const NAMESPACE = 'oidc';
 | 
			
		||||
 | 
			
		||||
i18n.addResources('zh-CN', NAMESPACE, zhCN);
 | 
			
		||||
i18n.addResources('en-US', NAMESPACE, enUS);
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ export default {
 | 
			
		||||
  Actions: '操作',
 | 
			
		||||
  Delete: '删除',
 | 
			
		||||
  Edit: '编辑',
 | 
			
		||||
  'Button title': '登录按钮标题',
 | 
			
		||||
  'OIDC manager': 'OIDC 管理',
 | 
			
		||||
  'OIDC Providers': 'OIDC 身份提供者',
 | 
			
		||||
  'Provider name': '名称',
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { ISchema } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { useActionContext, useRequest } from '@nocobase/client';
 | 
			
		||||
import { IDTOKEN_SIGN_ALG } from '../../server/shared/types';
 | 
			
		||||
 | 
			
		||||
@ -17,6 +16,17 @@ const collection = {
 | 
			
		||||
        required: true,
 | 
			
		||||
      } as ISchema,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      name: 'buttonTitle',
 | 
			
		||||
      interface: 'input',
 | 
			
		||||
      uiSchema: {
 | 
			
		||||
        title: '{{t("Button title")}}',
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        'x-component': 'Input',
 | 
			
		||||
        required: true,
 | 
			
		||||
      } as ISchema,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      name: 'clientId',
 | 
			
		||||
@ -169,6 +179,10 @@ export const formProperties = {
 | 
			
		||||
    'x-component': 'CollectionField',
 | 
			
		||||
    'x-decorator': 'FormItem',
 | 
			
		||||
  },
 | 
			
		||||
  buttonTitle: {
 | 
			
		||||
    'x-component': 'CollectionField',
 | 
			
		||||
    'x-decorator': 'FormItem',
 | 
			
		||||
  },
 | 
			
		||||
  clientId: {
 | 
			
		||||
    'x-component': 'CollectionField',
 | 
			
		||||
    'x-decorator': 'FormItem',
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
import { Context } from '@nocobase/actions';
 | 
			
		||||
 | 
			
		||||
export const getEnabledProviders = async (ctx: Context, next) => {
 | 
			
		||||
  const repository = ctx.db.getRepository('oidcProviders');
 | 
			
		||||
  ctx.body = await repository.find({
 | 
			
		||||
    filter: {
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    },
 | 
			
		||||
    fields: ['buttonTitle', 'clientId'],
 | 
			
		||||
  });
 | 
			
		||||
  return next();
 | 
			
		||||
};
 | 
			
		||||
@ -10,6 +10,10 @@ export default {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      name: 'title',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'buttonTitle',
 | 
			
		||||
      type: 'string',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      comment: '客户端id',
 | 
			
		||||
      type: 'string',
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
import UsersPlugin from '@nocobase/plugin-users';
 | 
			
		||||
import { InstallOptions, Plugin } from '@nocobase/server';
 | 
			
		||||
import { resolve } from 'path';
 | 
			
		||||
import { generators } from 'openid-client';
 | 
			
		||||
import { oidc } from './authenticators/oidc';
 | 
			
		||||
import { resolve } from 'path';
 | 
			
		||||
import { getAuthUrl } from './actions/getAuthUrl';
 | 
			
		||||
import { getEnabledProviders } from './actions/getEnabledProviders';
 | 
			
		||||
import { redirect } from './actions/redirect';
 | 
			
		||||
import { oidc } from './authenticators/oidc';
 | 
			
		||||
 | 
			
		||||
export class OidcPlugin extends Plugin {
 | 
			
		||||
  #OIDC_NONCE = null;
 | 
			
		||||
@ -20,7 +20,7 @@ export class OidcPlugin extends Plugin {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 获取 User 插件
 | 
			
		||||
    const userPlugin = this.app.getPlugin('users') as UsersPlugin;
 | 
			
		||||
    const userPlugin = this.app.getPlugin<any>('users');
 | 
			
		||||
 | 
			
		||||
    // 注册 OIDC 验证器
 | 
			
		||||
    userPlugin.authenticators.register('oidc', oidc);
 | 
			
		||||
@ -31,6 +31,7 @@ export class OidcPlugin extends Plugin {
 | 
			
		||||
      actions: {
 | 
			
		||||
        getAuthUrl,
 | 
			
		||||
        redirect,
 | 
			
		||||
        getEnabledProviders,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -46,7 +47,7 @@ export class OidcPlugin extends Plugin {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 开放访问权限
 | 
			
		||||
    this.app.acl.allow('oidcProviders', '*');
 | 
			
		||||
    this.app.acl.allow('oidcProviders', '*', 'allowConfigure');
 | 
			
		||||
    this.app.acl.allow('oidc', '*');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import React, { useEffect, useState, useRef } from 'react';
 | 
			
		||||
import { Button, Space } from 'antd';
 | 
			
		||||
import { LoginOutlined } from '@ant-design/icons';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { useAPIClient, useRedirect } from '@nocobase/client';
 | 
			
		||||
import { useAPIClient, useRedirect, useRequest } from '@nocobase/client';
 | 
			
		||||
import { Button, Space } from 'antd';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
 | 
			
		||||
export interface SAMLProvider {
 | 
			
		||||
  title: string;
 | 
			
		||||
@ -11,26 +11,14 @@ export interface SAMLProvider {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const SAMLList = () => {
 | 
			
		||||
  const [list, setList] = useState<SAMLProvider[]>([]);
 | 
			
		||||
  const [windowHandler, setWindowHandler] = useState<Window | undefined>();
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const redirect = useRedirect();
 | 
			
		||||
 | 
			
		||||
  const getSamlList = async () => {
 | 
			
		||||
    const { data: pluginsRes } = await api.request({
 | 
			
		||||
      url: 'app:getPlugins',
 | 
			
		||||
    });
 | 
			
		||||
    if (!(pluginsRes.data as string[]).includes('saml')) return;
 | 
			
		||||
    const { data: providersRes } = await api.request({
 | 
			
		||||
      url: 'samlProviders:list',
 | 
			
		||||
      params: {
 | 
			
		||||
        filter: {
 | 
			
		||||
          enabled: true,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    setList(providersRes.data);
 | 
			
		||||
  };
 | 
			
		||||
  const { data, loading } = useRequest({
 | 
			
		||||
    resource: 'saml',
 | 
			
		||||
    action: 'getEnabledProviders',
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 打开登录弹出框
 | 
			
		||||
@ -79,10 +67,6 @@ export const SAMLList = () => {
 | 
			
		||||
    };
 | 
			
		||||
  }, [windowHandler]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    getSamlList();
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Space
 | 
			
		||||
      direction="vertical"
 | 
			
		||||
@ -90,9 +74,9 @@ export const SAMLList = () => {
 | 
			
		||||
        display: flex;
 | 
			
		||||
      `}
 | 
			
		||||
    >
 | 
			
		||||
      {list.map((item) => (
 | 
			
		||||
      {data?.data?.map?.((item) => (
 | 
			
		||||
        <Button shape="round" block key={item.clientId} icon={<LoginOutlined />} onClick={() => handleOpen(item)}>
 | 
			
		||||
          SAML: {item.title}
 | 
			
		||||
          {item.buttonTitle}
 | 
			
		||||
        </Button>
 | 
			
		||||
      ))}
 | 
			
		||||
    </Space>
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,13 @@
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { i18n } from '@nocobase/client';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
 | 
			
		||||
import zhCN from './zh-CN';
 | 
			
		||||
import enUS from './en-US';
 | 
			
		||||
import jaJP from './ja-JP';
 | 
			
		||||
import ruRU from './ru-RU';
 | 
			
		||||
import trTR from './tr-TR';
 | 
			
		||||
import zhCN from './zh-CN';
 | 
			
		||||
 | 
			
		||||
export const NAMESPACE = 'workflow';
 | 
			
		||||
export const NAMESPACE = 'saml';
 | 
			
		||||
 | 
			
		||||
i18n.addResources('zh-CN', NAMESPACE, zhCN);
 | 
			
		||||
i18n.addResources('en-US', NAMESPACE, enUS);
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ export default {
 | 
			
		||||
  Actions: '操作',
 | 
			
		||||
  Title: '身份提供者名称',
 | 
			
		||||
  Enable: '启用',
 | 
			
		||||
  'Button title': '登录按钮标题',
 | 
			
		||||
  'SAML manager': 'SAML 管理',
 | 
			
		||||
  'SAML Providers': 'SAML 身份提供者',
 | 
			
		||||
  'Redirect url': '重定向地址',
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,17 @@ const collection = {
 | 
			
		||||
        required: true,
 | 
			
		||||
      } as ISchema,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      name: 'buttonTitle',
 | 
			
		||||
      interface: 'input',
 | 
			
		||||
      uiSchema: {
 | 
			
		||||
        title: '{{t("Button title")}}',
 | 
			
		||||
        type: 'string',
 | 
			
		||||
        'x-component': 'Input',
 | 
			
		||||
        required: true,
 | 
			
		||||
      } as ISchema,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      name: 'clientId',
 | 
			
		||||
@ -98,6 +109,10 @@ export const formProperties = {
 | 
			
		||||
    'x-component': 'CollectionField',
 | 
			
		||||
    'x-decorator': 'FormItem',
 | 
			
		||||
  },
 | 
			
		||||
  buttonTitle: {
 | 
			
		||||
    'x-component': 'CollectionField',
 | 
			
		||||
    'x-decorator': 'FormItem',
 | 
			
		||||
  },
 | 
			
		||||
  clientId: {
 | 
			
		||||
    'x-component': 'CollectionField',
 | 
			
		||||
    'x-decorator': 'FormItem',
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
import { Context } from '@nocobase/actions';
 | 
			
		||||
 | 
			
		||||
export const getEnabledProviders = async (ctx: Context, next) => {
 | 
			
		||||
  const repository = ctx.db.getRepository('samlProviders');
 | 
			
		||||
  ctx.body = await repository.find({
 | 
			
		||||
    filter: {
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    },
 | 
			
		||||
    fields: ['buttonTitle', 'clientId'],
 | 
			
		||||
  });
 | 
			
		||||
  return next();
 | 
			
		||||
};
 | 
			
		||||
@ -9,6 +9,10 @@ export default {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      name: 'title',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      name: 'buttonTitle',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      comment: '客户端id',
 | 
			
		||||
      type: 'string',
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
import UsersPlugin from 'packages/plugins/users/src/server';
 | 
			
		||||
import { InstallOptions, Plugin } from '@nocobase/server';
 | 
			
		||||
import { resolve } from 'path';
 | 
			
		||||
import { saml } from './authenticators/saml';
 | 
			
		||||
import { redirect } from './actions/redirect';
 | 
			
		||||
import { metadata } from './actions/metadata';
 | 
			
		||||
import { getAuthUrl } from './actions/getAuthUrl';
 | 
			
		||||
import { getEnabledProviders } from './actions/getEnabledProviders';
 | 
			
		||||
import { metadata } from './actions/metadata';
 | 
			
		||||
import { redirect } from './actions/redirect';
 | 
			
		||||
import { saml } from './authenticators/saml';
 | 
			
		||||
 | 
			
		||||
export class SAMLPlugin extends Plugin {
 | 
			
		||||
  afterAdd() {}
 | 
			
		||||
@ -18,7 +18,7 @@ export class SAMLPlugin extends Plugin {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 获取 User 插件
 | 
			
		||||
    const userPlugin = this.app.getPlugin('users') as UsersPlugin;
 | 
			
		||||
    const userPlugin = this.app.getPlugin<any>('users');
 | 
			
		||||
 | 
			
		||||
    // 注册 SAML 验证器
 | 
			
		||||
    userPlugin.authenticators.register('saml', saml);
 | 
			
		||||
@ -30,11 +30,12 @@ export class SAMLPlugin extends Plugin {
 | 
			
		||||
        redirect,
 | 
			
		||||
        metadata,
 | 
			
		||||
        getAuthUrl,
 | 
			
		||||
        getEnabledProviders,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 开放访问权限
 | 
			
		||||
    this.app.acl.allow('samlProviders', '*');
 | 
			
		||||
    this.app.acl.allow('samlProviders', '*', 'allowConfigure');
 | 
			
		||||
    this.app.acl.allow('saml', '*');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit 5a5fba41ae1cecaf3b073fcb610e9dc68dad0b85
 | 
			
		||||
Subproject commit cf44c47ff9b5ef41e8becde3f1c8b5b1c2af6cda
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user