アクセス制御とは、保護されたリソースへの訪問者によるアクセス操作の制御と管理を指します。この制御管理により、許可された人は保護されたリソースにアクセスでき、許可されていない人は保護されたリソースにアクセスできなくなります。
実際のアクセス制御は、支払いまたは認証によって実現できます。たとえば、映画を見に映画館に行く場合は、映画のチケットを購入するのに十分な金額が必要です。そうしないと、チケット検査官はあなたを入れません。
アクセス制御には、次のような多くのモデルがあります。
- 随意アクセス制御
- 強制アクセス制御モデル(MAC:強制アクセス制御)
- 役割ベースのアクセス制御(RBAC:役割ベースのアクセス制御)
- 属性アクセス制御モデル(ABAC:属性ベースのアクセス制御)
DAC
随意アクセス制御(DAC:随意アクセス制御)。システムはユーザーを識別し、アクセス制御リスト(ACL:アクセス制御リスト)またはアクセス制御マトリックスの情報に基づいて、ユーザーがアクセスオブジェクトにアクセスできるかどうかを判断します。 (ACL:アクセス制御マトリックス)。読み取りや変更など、実行する操作。オブジェクト権限を持つユーザーは、オブジェクト権限を他のユーザーに割り当てることができるため、「随意」制御と呼ばれます。
随意アクセス制御モデルは、リソースを不正アクセスや不正使用から保護するための比較的緩いが効果的な手段です。自律的に制御されているため緩いと言われ、リソースを保護する際の個人的な意思に基づいており、対象がオブジェクトにアクセスまたは使用していることを明確に指摘できるため効果的です。 、指定された権限を超えるアクセス動作は、アクセス制御リストによって決定され、ブロックされます。
典型的なシナリオはLinuxファイルシステムです。システム内のすべてのファイル(ブロックデバイスファイルなど、一部の特殊ファイルには所有者がいない場合があります)に所有者がいます。ファイルの所有者は、ファイルを作成したコンピューターのユーザー(またはイベント、または別のファイル)です。次に、このファイルの任意アクセス制御権は、設定および割り当てる作成者によって決定されます。ファイルの所有者はアクセス権を持ち、自分自身と他のユーザーにアクセス権を割り当てることができます
マック
強制アクセス制御(MAC:強制アクセス制御)。分類と分類によってシステム内の情報を管理し、各ユーザーがマークされたアクセス制御下のユーザー(または他のサブジェクト)とファイルにのみアクセスできるようにするために使用されます。他のオブジェクト)は固定のセキュリティ属性(セキュリティレベル、アクセス権など)でマークされ、アクセスが発生するたびに、システムはセキュリティ属性をチェックして、ユーザーがファイルにアクセスできるかどうかを判断します。
MACは、最初は主に軍用アプリケーションで使用され、通常はDACと組み合わせて使用されました。2つのアクセス制御メカニズムのフィルタリング結果は、より優れたアクセス制御効果を実現するために蓄積されます。つまり、被験者は、DAC制限チェックとMAC制限チェックの二重フィルタリングデバイスに合格した後にのみ、実際にオブジェクトにアクセスできます。一方では、ユーザーはDACを使用して、所有権が自分に属するオブジェクトを他のユーザーが攻撃するのを防ぐことができます。他のユーザーによるDACの偶発的または意図的な誤用を防ぐことができます。
RBAC
ロールベースのアクセス制御(RBAC:ロールベースのアクセス制御)では、特定のユーザーにさまざまなアクセス許可が直接付与されることはありませんが、ユーザーセットとアクセス許可セットの間にロールセットが確立されます。各役割は、対応する一連の権限に対応しています。ユーザーに適切な役割が割り当てられると、そのユーザーはその役割のすべての操作権限を持ちます。現在、役割ベースのアクセス制御モデルは、特に2B方向のSAAS分野で最も広く使用されているモデルの1つです。今日は焦点を当てます。
RBACは権限の管理を簡素化しますが、複雑なシナリオでの役割管理にはまだ十分な柔軟性がありません。たとえば、サブジェクトとオブジェクト間の権限は複雑で変更可能であり、多数のロールとそれらの承認関係を維持する必要がある場合があります。新しいオブジェクトもすべての関連するロールを処理する必要があります。属性ベースの役割アクセス制御は、この問題を解決するように設計されています。
ABAC
属性ベースのアクセス制御は、非常に柔軟なアクセス制御モデルです。属性には、リクエスト本文の属性、リクエストオブジェクトの属性、リクエストコンテキストの属性、操作の属性などが含まれます。たとえば、校長(教科の属性)であるラオ・チャンは、クラス(文脈の属性)にいるときに、普通の学生(オブジェクトの属性)であるシャオミンを蹴る(操作の属性)ことができます。属性が正確に定義および分割されている限り、ABACは非常に複雑な権限制御を実現できることがわかります。
たとえば、2年生(学年)の会計(メジャー)クラス(クラス)のクラス幹部(位置)は、学校のイントラネット(環境)にクラスの写真をアップロード(操作)できます。
ただし、ABACは複雑であるため、現在のSAASフィールドでは少しやり過ぎです。したがって、SAASフィールドでABACを使用するプラットフォームはほとんどありません。現在、ABACは一部のクラウドサービスで主に使用されています。
スタック内のRBAC
当社の製品ではRBACの許可スキームが使用されているため、現在はRBACのみを分析しています。
RBACはロールアクセス制御であるため、最初に知っておく必要があるのはユーザーのロールです。この点で、プロジェクトにはユーザー管理とロール管理の2つのモジュールがあります。
ユーザー管理
uicのユーザー管理でユーザーアカウントの作成、編集、削除などの機能を提供します。
。
Shuixun製品にはテナントがあり、各テナントの下にはテナント内のユーザーを管理するためのユーザー管理もあります。現在のユーザーの役割を設定する機能。これらの役割には、テナント所有者、プロジェクト所有者、プロジェクトマネージャーなどが含まれます。
。
役割管理
ロール管理では、ロールの定義とロールが持つアクセス権を確認できます。
。
ユーザー管理とロール管理のユーザー定義により、現在のユーザーの完全な製品アクセス権を取得できます。ユーザーが関数に入ると、現在のアクセス権とユーザーのアクセス権を比較して、認めるかどうか。
私たちのフロントエンド開発者にとって、私たちが必要としているのは実際には
- ユーザーの役割権限を取得する
- 取得した権限を使用して、結果を異なる方法で比較および処理します
次に、antdesignproの許可スキームがどのように処理されるかを見てみましょう。
antデザインプロの許可スキーム
業界でより一般的なantdesignproの許可スキームはどのように設計されていますか?
ユーザーロールの権限を取得する
最初に、ページに入るときに、ログイン検証が実行されます。ログインしていない場合は、ログインページにジャンプしてログイン操作を実行します。ログインが成功すると、現在のユーザーの役割データがsetAuthorityメソッドを介してlocalStorageに保存され、取得できるようになります。ページに再度入るとき。ログイン確認に合格した方は、直接プロジェクトに入り、ページの基本的なレイアウトをレンダリングします。後続の権限チェックでは、重要なCURRENTが使用されます。
。
renderAuthorizeメソッドは、内部でgetAuthorityを使用してロールデータを取得するときにCURRENTに値を割り当てるカリー化関数です。
let CURRENT: string | string[] = 'NULL';
type CurrentAuthorityType = string | string[] | (() => typeof CURRENT);
/**
* use authority or getAuthority
* @param {string|()=>String} currentAuthority
*/
const renderAuthorize = (Authorized: any) => (currentAuthority: CurrentAuthorityType) => {
if (currentAuthority) {
if (typeof currentAuthority === 'function') {
CURRENT = currentAuthority();
}
if (
Object.prototype.toString.call(currentAuthority) === '[object String]' ||
Array.isArray(currentAuthority)
) {
CURRENT = currentAuthority as string[];
}
} else {
CURRENT = 'NULL';
}
return Authorized;
};
export { CURRENT };
export default (Authorized: any) => renderAuthorize(Authorized);
この時点で、プロジェクトの許可の取得と更新が完了します。次のステップは、権限を確認することです。
権限を確認する
権限の検証には、次の環境パラメーターが必要です。
- 権限:現在のアクセス権限はアクセス権限です
- currentAuthority:現在のユーザーの役割。これはCURRENTです。
- ターゲット:正常に表示されたコンポーネントを確認します
- 例外:検証でコンポーネントを表示できませんでした
権限の確認が必要なコンポーネントの場合は、承認されたコンポーネントを使用して結合します。承認されたコンポーネント内に、checkPermissionsメソッドが実装され、現在のユーザーロールと、アクセスする権限があるかどうかが確認されます。許可がある場合は現在のコンポーネントが直接表示され、許可されていない場合は「許可なし」などのメッセージが表示されます。
。
許可されたコンポーネントの実装
type IAuthorizedType = React.FunctionComponent<AuthorizedProps> & {
Secured: typeof Secured;
check: typeof check;
AuthorizedRoute: typeof AuthorizedRoute;
};
const Authorized: React.FunctionComponent<AuthorizedProps> = ({
children,
authority,
noMatch = (
<Result
status="403"
title="403"
subTitle="Sorry, you are not authorized to access this page."
/>
),
}) => {
const childrenRender: React.ReactNode = typeof children === 'undefined' ? null : children;
const dom = check(authority, childrenRender, noMatch);
return <>{dom}</>;
};
function check<T, K>(authority: IAuthorityType, target: T, Exception: K): T | K | React.ReactNode {
return checkPermissions<T, K>(authority, CURRENT, target, Exception);
}
/**
* 通用权限检查方法
* Common check permissions method
* @param { 权限判定 | Permission judgment } authority
* @param { 你的权限 | Your permission description } currentAuthority
* @param { 通过的组件 | Passing components } target
* @param { 未通过的组件 | no pass components } Exception
*/
const checkPermissions = <T, K>(
authority: IAuthorityType,
currentAuthority: string | string[],
target: T,
Exception: K,
): T | K | React.ReactNode => {
// 没有判定权限.默认查看所有
// Retirement authority, return target;
if (!authority) {
return target;
}
// 数组处理
if (Array.isArray(authority)) {
if (Array.isArray(currentAuthority)) {
if (currentAuthority.some((item) => authority.includes(item))) {
return target;
}
} else if (authority.includes(currentAuthority)) {
return target;
}
return Exception;
}
// string 处理
if (typeof authority === 'string') {
if (Array.isArray(currentAuthority)) {
if (currentAuthority.some((item) => authority === item)) {
return target;
}
} else if (authority === currentAuthority) {
return target;
}
return Exception;
}
// Promise 处理
if (authority instanceof Promise) {
return <PromiseRender<T, K> ok={target} error={Exception} promise={authority} />;
}
// Function 处理
if (typeof authority === 'function') {
const bool = authority(currentAuthority);
// 函数执行后返回值是 Promise
if (bool instanceof Promise) {
return <PromiseRender<T, K> ok={target} error={Exception} promise={bool} />;
}
if (bool) {
return target;
}
return Exception;
}
throw new Error('unsupported parameters');
};
許可されたコンポーネントの使用
ページ上での使用は非常に便利です。管理および制御が必要なコンポーネントについては、承認されたコンポーネントを使用してそれらを組み合わせることができます。
function NoMatch = () => {
return <div>404</div>
}
<Authorized authority={'admin'} noMatch={NoMatch}>
{children}
</Authorized>
ルーティングを使用してコンポーネントを照合することもできます。これは、v4での使用であり、コンポーネントがどこに記述されていても、サブコンポーネントがレンダリングされる場所にのみ一致します。
<Authorized
authority={authority}
noMatch={<Route {...rest} render={() => <Redirect to={{ pathname: redirectPath }} />} />}
>
<Route
{...rest}
render={(props: any) => (Component ? <Component {...props} /> : render(props))}
/>
</Authorized>
私たちの許可スキーム
現在、2セットの権限があります。1つはオフライン品質などの製品で使用されている古い権限スキームであり、もう1つはアセットタグで使用されている新しい権限スキームです。
古い許可スキーム
従来の方式では、インターフェースを介してデータを取得する方法が採用されていましたが、取得したデータはメニューレベルのみです。取得したデータはキャッシュに保存され、ビジネスパッケージやサブ製品での使用に便利です。サービスパッケージ内のページアドレスの変更を監視し、現在のページに入る権限があるかどうかを判断し、結果に応じて対応する処理を実行します。これは実際にはルーティングガードの機能です。サブプロダクトでは、データに基づいて現在のメニューエントリを表示するかどうかが判断されます。2つの組み合わせは、私たちの古いスキームを形成します。
データスタックの成長に伴い、古いソリューションは徐々に多くの問題を露呈しました。
- 権限制御の範囲が小さすぎるため、メニューのレベルのみを制御します。特別なページや、機能(編集、追加、削除など)の制御を必要とする特定のシナリオでは、現在はバックエンドのみを制御します。インターフェイスは制限されており、ページに制限はありません。この機能を実装する必要がある場合は、インターフェイスと処理ロジックを追加する必要があります。
- パーミッションの処理をビジネスパッケージとサブプロダクトの2つの部分に分割しますが、2つの間の結合は非常に高く、多くの場合、一方の場所を変更すると、もう一方の場所も変更する必要があります。
- ビジネスパッケージでは、各商品のページアクセスロジックを制御します。メニューを追加する必要がある場合は常に、対応するメニュー処理ロジックを追加する必要があります。商品を追加する場合は、これに対応するすべてのメニューロジックを追加する必要があります。現在、データスタックサブ製品の数が10以上を超えているため、処理ロジックのこの部分がどれほど肥大化しているかを想像できます。
実際の問題は上記の3つのポイント以上ですが、これらの3つのポイントは、新しい許可スキームを検討するのに十分です。
新しい許可スキーム
新しいソリューションでは、ビジネスパッケージはアクセス許可のパブリックメソッドのみを保持し、ページアクセス許可の判断のロジックを分散化します。サブ製品は独自のアクセス許可の判断ロジックを維持し、アクセス許可のロジックを変更することも非常に簡単です。
。
ant design proでの役割による判断と比較して、新しいスキームでは、役割の権限の判断ロジックをバックエンドに転送し、バックエンドは対応する処理の後に対応するコードコードセットを返します。
アクセス許可を設定する必要がある各モジュールのコードコードを定義し、バックエンドによって返されるコレクションで同じコードが見つかるかどうかを比較します。
これを行った後、私たちは入ることができるかどうかだけを気にする必要があります。
パーミッションポイントを取得すると、このパーミッションポイントに従ってアクセス許可のあるルートリストもキャッシュされます。ルートが変更された場合は、許可ルートリストに移動して検索できます。見つからない場合はリダイレクトされます。 、などの操作、つまりルーティングガードの機能。
要約する
上記の紹介の後、許可スキームについてある程度理解しました。これは主に2つの段階に分かれています。
- 権限取得段階:権限取得段階では、ユーザーがプロジェクトにログインまたは入力すると、最初にユーザー情報に従って対応する権限が取得されます。
- パーミッション検証段階:ユーザーのパーミッションにより、現在のモジュールのアクセスパーミッションと比較し、その結果に応じて動作します。
これを知った後、あなたはあなた自身のシナリオに基づいて対応する許可計画を策定することができます。