apache-shiro-access-control
Apache Shiroによるアクセス許可ベースのアクセス制御
-
link:/category/security-2/ [セキュリティ]
1. 前書き
このチュートリアルでは、https://www.baeldung.com/apache-shiro [Apache Shiro] Javaセキュリティフレームワークを使用して、*きめ細かいアクセス許可ベースのアクセス制御*を実装する方法について説明します。
2. セットアップ
Shiroの紹介と同じセットアップを使用します。つまり、https://search.maven.org/search?q = g:org.apache.shiro%20AND%20a:shiro-のみを追加します。 core&core = gav [_shiro-core_]モジュールと依存関係:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
さらに、テスト目的で、次の_shiro.ini_ファイルをクラスパスのルートに配置することにより、単純なINIレルムを使用します。
[users]
jane.admin = password, admin
john.editor = password2, editor
zoe.author = password3, author
[roles]
admin = *
editor = articles:*
author = articles:create, articles:edit
次に、上記の領域でShiroを初期化します。
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
SecurityManager securityManager = new DefaultSecurityManager(iniRealm);
SecurityUtils.setSecurityManager(securityManager);
3. 役割と権限
通常、認証と承認について話すときは、ユーザーとロールの概念に注目します。
特に、*ロールはアプリケーションまたはサービスのユーザーの横断的なクラスです*。したがって、特定のロールを持つすべてのユーザーは一部のリソースと操作にアクセスでき、アプリケーションまたはサービスの他の部分へのアクセスが制限される可能性があります。
ロールのセットは通常、事前に設計されており、新しいビジネス要件に対応するために変更されることはほとんどありません。 ただし、役割は、管理者などによって動的に定義することもできます。
Shiroでは、ユーザーに特定の役割があるかどうかをテストする方法がいくつかあります。 最も簡単な方法は、_hasRole_メソッドを使用することです。
Subject subject = SecurityUtils.getSubject();
if (subject.hasRole("admin")) {
logger.info("Welcome Admin");
}
* 3.1。 権限*
ただし、ユーザーが特定の役割を持っているかどうかをテストして承認を確認する場合は問題があります。 実際、ロールとアクセス許可の関係をハードコーディングしています。つまり、リソースへのアクセスを許可または取り消したい場合は、ソースコードを変更する必要があります。 もちろん、これは再構築と再展開も意味します。
もっとうまくできるこれが、アクセス許可の概念を紹介する理由です。 *許可とは、ソフトウェアが実行できること*、許可または拒否できること、および誰が実行できることではないかを示します。*たとえば、「現在のユーザーのプロファイルを編集する」、「ドキュメントを承認する」、または「新しい記事を作成する」。
Shiroは、許可についてほとんど仮定しません。 最も単純な場合、許可はプレーンな文字列です。
Subject subject = SecurityUtils.getSubject();
if (subject.isPermitted("articles:create")) {
//Create a new article
}
-
Shiroでは、権限の使用は完全にオプションです*。
* 3.2。 アクセス許可をユーザーに関連付ける*
Shiroには、権限をロールまたは個々のユーザーに関連付ける柔軟なモデルがあります。 ただし、このチュートリアルで使用している単純なINIレルムを含む典型的なレルムは、ロールにパーミッションのみを関連付けます。
そのため、_Principal、_で識別されるユーザーには複数のロールがあり、各ロールには複数の__Permission__sがあります。
たとえば、INIファイルでは、ユーザー_zoe.author_に_author_ロールがあり、_articles:create_および_articles:edit_パーミッションが付与されていることがわかります。
[users]
zoe.author = password3, author
#Other users...
[roles]
author = articles:create, articles:edit
#Other roles...
同様に、他のレルムタイプ(組み込みJDBCレルムなど)をコンフィグレーションして、パーミッションをロールに関連付けることができます。
4. ワイルドカード許可
-
Shiroのパーミッションのデフォルト実装はワイルドカードパーミッションです*、さまざまなパーミッションスキームの柔軟な表現です。
Shiroのワイルドカード許可を文字列で表します。 許可文字列は、次のようなコロンで区切られた1つ以上のコンポーネントで構成されます。
articles:edit:1
Shiroはルールを強制しないため、文字列の各部分の意味はアプリケーションによって異なります。 ただし、上記の例では、文字列を階層として非常に明確に解釈できます。
-
公開しているリソースのクラス(記事)
-
そのようなリソースに対するアクション(編集)
-
を許可または拒否する特定のリソースのID
アクションresource:action:idのこの3層構造は、多くの異なるシナリオを表現するのにシンプルかつ効果的であるため、Shiroアプリケーションの一般的なパターンです。
したがって、このスキームに従うために前の例を再検討できます。
Subject subject = SecurityUtils.getSubject();
if (subject.isPermitted("articles:edit:123")) {
//Edit article with id 123
}
-
3つのコンポーネントが通常の場合でも、ワイルドカード許可文字列のコンポーネントの数は3である必要はありません。*
* 4.1。 権限の含意とインスタンスレベルの粒度*
ワイルドカードのアクセス許可は、Shiroのアクセス許可の別の機能(含意)と組み合わせることで向上します。
*ロールをテストするとき、正確なメンバーシップをテストします:* _Subject_が特定のロールを持っているか、持っていないかのどちらかです。 つまり、Shiroはロールの平等をテストします。
一方、*権限をテストするときは、含意をテストします*。_Subject_ ’の権限は、テスト対象の権限を意味しますか?
具体的に意味するものは、許可の実装に依存します。 実際、ワイルドカード許可の場合、意味は名前が示唆するように、ワイルド文字列の可能性を伴う部分的な文字列の一致です。
したがって、_author_ロールに次のアクセス許可を割り当てたとします。
[roles]
author = articles:*
次に、__ author __roleを持つすべてのユーザーに、記事に対するすべての可能な操作が許可されます。
Subject subject = SecurityUtils.getSubject();
if (subject.isPermitted("articles:create")) {
//Create a new article
}
つまり、文字列_articles:* _は、最初のコンポーネントが_articles._であるワイルドカード許可と一致します
このスキームでは、特定のIDを持つ特定のリソースに対する特定のアクション、または記事の編集や記事に対する操作の実行など、非常に具体的な権限を割り当てることができます。
もちろん、パフォーマンス上の理由から、含意は単純な等価比較ではないため、*最も具体的な権限に対して常にテストする必要があります*:
if (subject.isPermitted("articles:edit:1")) { //Better than "articles:*"
//Edit article
}
5. カスタム許可の実装
権限のカスタマイズについて簡単に触れてみましょう。 ワイルドカードのアクセス許可は広範囲のシナリオに対応していますが、アプリケーション用にカスタマイズされたソリューションに置き換えたい場合があります。
すべてのサブパスで_implies_許可を許可するように、パスで許可をモデル化する必要があるとします。 実際には、タスクにワイルドカード権限を使用できますが、それは無視しましょう。
それで、何が必要ですか?
-
_Permission_実装
-
それを史郎に伝えるために
両方のポイントを達成する方法を見てみましょう。
* 5.1。 許可の実装の作成*
-
_Permission_実装は、単一のメソッドを持つクラスです— _implies _:*
public class PathPermission implements Permission {
private final Path path;
public PathPermission(Path path) {
this.path = path;
}
@Override
public boolean implies(Permission p) {
if(p instanceof PathPermission) {
return ((PathPermission) p).path.startsWith(path);
}
return false;
}
}
このメソッドは、__ this_が_true_を返し、他の許可オブジェクトを暗黙指定し、そうでない場合は_false_を返します。
* 5.2。 実装についてシロに伝える*
次に、__ Permission __implementationをShiroに統合するさまざまな方法がありますが、最も簡単な方法は*カスタム_PermissionResolver_を_Realm _:*に挿入することです
IniRealm realm = new IniRealm();
Ini ini = Ini.fromResourcePath(Main.class.getResource("/com/.../shiro.ini").getPath());
realm.setIni(ini);
realm.setPermissionResolver(new PathPermissionResolver());
realm.init();
SecurityManager securityManager = new DefaultSecurityManager(realm);
-
_PermissionResolver_が責任を持ちます* * *権限の文字列表現を実際の_Permission_オブジェクトに変換します:
public class PathPermissionResolver implements PermissionResolver {
@Override
public Permission resolvePermission(String permissionString) {
return new PathPermission(Paths.get(permissionString));
}
}
以前の_shiro.ini_をパスベースのアクセス許可で変更する必要があります。
[roles]
admin = /
editor = /articles
author = /articles/drafts
次に、パスのアクセス許可を確認できます。
if(currentUser.isPermitted("/articles/drafts/new-article")) {
log.info("You can access articles");
}
ここでは、単純なレルムをプログラムで構成していることに注意してください。 典型的なアプリケーションでは、_shiro.ini_ファイルまたはSpringなどの他の手段を使用して、Shiroとレルムを構成します。 実世界のs_shiro.ini_ファイルには次のものが含まれます。
[main]
permissionResolver = com.baeldung.shiro.permissions.custom.PathPermissionResolver
dataSource = org.apache.shiro.jndi.JndiObjectFactory
dataSource.resourceName = java://app/jdbc/myDataSource
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource = $dataSource
jdbcRealm.permissionResolver = $permissionResolver
6. 結論
この記事では、Apache Shiroがパーミッションベースのアクセス制御を実装する方法を確認しました。
いつものように、これらすべての例とコードスニペットの実装は、https://github.com/eugenp/tutorials/tree/master/apache-shiro [GitHubで]で入手できます。