ホームページ  >  記事  >  Java  >  SpringBoot が Sa-Token を使用してパーミッション認証を実装する方法

SpringBoot が Sa-Token を使用してパーミッション認証を実装する方法

PHPz
PHPz転載
2023-05-16 13:19:131153ブラウズ

1. 設計アイデア

いわゆる権限認証、コア ロジックは、アカウントが指定された権限を持っているかどうかを判断することです:

  • そうであれば、あなたは、通過が許可されます。 ############いいえ?それではアクセス禁止です!

  • 基礎となるデータを詳しく調べると、各アカウントには一連の権限コードがあり、フレームワークはこのセットに指定された権限コードが含まれているかどうかを確認します。

  • 例: 現在のアカウントには権限コード セット
["user-add", "user-delete", "user-get"]

が設定されている場合、権限を確認します

"user-update"

、結果は次のようになります: 検証に失敗しました。 へのアクセスは禁止されています。 それでは、問題の核心は次のとおりです:

アカウントが所有する許可コードのセットを取得するにはどうすればよいでしょうか?

  • この操作ではどの権限コードを確認する必要がありますか?

  • 次に、Sa-Token を使用して SpringBoot で権限認証操作を完了する方法を紹介します。

Sa-Token は、ログイン認証、権限認証、シングル サインオン、OAuth3、マイクロサービス ゲートウェイ認証などの権限関連の一連の問題を主に解決する軽量の Java 権限認証フレームワークです。

まず、Sa-Token 依存関係をプロジェクトに導入します:

<!-- Sa-Token 权限认证 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.34.0</version>
</dependency>

注:
SpringBoot 3.x

を使用している場合は、## を追加するだけです。 #sa -token-spring-boot-starter

sa-token-spring-boot3-starter に変更できます。 2. 現在のアカウント権限コード セットを取得します各プロジェクトには異なるニーズがあり、権限の設計も常に変化しているため、[現在のアカウント権限コード セットを取得する] は構築できませんSa-Token はこの操作をインターフェイスの形式で公開するため、独自のビジネス ロジックに従って書き換えることができます。

あなたがする必要があるのは、新しいクラスを作成し、次のコードのような

StpInterface

インターフェースを実装することです:

/**
 * 自定义权限验证接口扩展
 */
@Component	// 保证此类被SpringBoot扫描,完成Sa-Token的自定义权限验证扩展 
public class StpInterfaceImpl implements StpInterface {

	/**
	 * 返回一个账号所拥有的权限码集合 
	 */
	@Override
	public List<String> getPermissionList(Object loginId, String loginType) {
		// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
		List<String> list = new ArrayList<String>();	
		list.add("101");
		list.add("user.add");
		list.add("user.update");
		list.add("user.get");
		// list.add("user.delete");
		list.add("art.*");
		return list;
	}

	/**
	 * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
	 */
	@Override
	public List<String> getRoleList(Object loginId, String loginType) {
		// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色
		List<String> list = new ArrayList<String>();	
		list.add("admin");
		list.add("super-admin");
		return list;
	}

}

パラメータの説明:

loginId: アカウント ID。StpUtil.login(id)

を呼び出すときに書き込む識別値です。
  • loginType: アカウント システム識別子、ここでは一時的に無視できます。この概念については、[複数アカウント認証] の章で詳しく説明します。

  • 注: コンポーネントが Springboot によってスキャンされ、Sa-Token に正常に挿入されるようにするには、

    クラスに
  • @Component
アノテーションを付ける必要があります。枠内で。

3. 権限の検証スタートアップ クラス:

@SpringBootApplication
public class SaTokenCaseApplication {
	public static void main(String[] args) {
		SpringApplication.run(SaTokenCaseApplication.class, args); 
		System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
	}	
}

次に、次の API を使用して

// 获取:当前账号所拥有的权限集合
StpUtil.getPermissionList();

// 判断:当前账号是否含有指定权限, 返回 true 或 false
StpUtil.hasPermission("user.add");		

// 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException 
StpUtil.checkPermission("user.add");		

// 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过]
StpUtil.checkPermissionAnd("user.add", "user.delete", "user.get");		

// 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
StpUtil.checkPermissionOr("user.add", "user.delete", "user.get");	

拡張機能を認証できます:

NotPermissionException

オブジェクトは、

getLoginType()

メソッド

4 を通じて StpLogic がスローされる特定の例外を取得できます。 ロールの検証In Sa -Inトークン、ロール、権限は個別に検証できます

// 获取:当前账号所拥有的角色集合
StpUtil.getRoleList();

// 判断:当前账号是否拥有指定角色, 返回 true 或 false
StpUtil.hasRole("super-admin");		

// 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
StpUtil.checkRole("super-admin");		

// 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
StpUtil.checkRoleAnd("super-admin", "shop-admin");		

// 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] 
StpUtil.checkRoleOr("super-admin", "shop-admin");		

拡張機能:

NotRoleException

オブジェクトは

getLoginType()

メソッドを通じて取得できます

StpLogic スロー例外5. グローバル例外のインターセプト学生の中には、認証が失敗して例外がスローされた場合はどうなるのか、と尋ねたい人もいます。ユーザーに例外を表示しますか? ###もちろん違います!

グローバル例外インターセプターを作成して、フロントエンドに返される形式を統一できます。参考:

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 全局异常拦截 
    @ExceptionHandler
    public SaResult handlerException(Exception e) {
        e.printStackTrace(); 
        return SaResult.error(e.getMessage());
    }
}

6. 許可ワイルドカードSa-Token を使用すると、次のことが可能になります。ワイルドカードに

general 権限

を指定します。たとえば、アカウントに

art.*

art.add

art.delete## の権限がある場合です。 #, art.update は、

// 当拥有 art.* 权限时
StpUtil.hasPermission("art.add");        // true
StpUtil.hasPermission("art.update");     // true
StpUtil.hasPermission("goods.add");      // false

// 当拥有 *.delete 权限时
StpUtil.hasPermission("art.delete");      // true
StpUtil.hasPermission("user.delete");     // true
StpUtil.hasPermission("user.update");     // false

// 当拥有 *.js 权限时
StpUtil.hasPermission("index.js");        // true
StpUtil.hasPermission("index.css");       // false
StpUtil.hasPermission("index.html");      // false
God 権限によって照合されます。アカウントに "*" 権限がある場合、アカウントは任意の権限コードを通じて認証できます。 (ロールは認証でも同じ)

7. 権限をボタン レベルまで正確に設定するにはどうすればよいですか?

ボタン レベルまで正確な権限とは、権限スコープはページ上の各ボタンに を表示するかどうかを制御できることを意味します。

アイデア: このような正確な範囲制御は、バックエンドのみに依存して実現するのは難しく、このとき、フロントエンドは一定の論理的判断を行う必要があります。

フロントエンドとバックエンドが統合されたプロジェクトの場合は、Thymeleaf タグ方言を参照できます。フロントエンドとバックエンドが分離されたプロジェクトの場合は、

ログインすると、現在のアカウントのすべての権限コードが一度にフロントエンドに返されます。

フロントエンドは、権限コード コレクションを
    localStorage
  • またはその他のグローバル状態管理オブジェクトに保存します。

  • 権限制御が必要なボタンについては、js を使用して論理的に判断します。たとえば、

    Vue フレームワークでは、次のような記述が使用できます。 ##

    <button v-if="arr.indexOf(&#39;user.delete&#39;) > -1">删除按钮</button>

    その内:
  • arr
  • は現在のユーザーが所有する権限コード配列、

    user.delete はボタンを表示するために必要な権限コード、削除ボタン

    許可コードを持っているユーザーのみが閲覧できるコンテンツです。
注: 上記の記述方法は参考例であり、フレームワークごとに記述方法が異なるため、プロジェクトの技術スタックに応じて柔軟にカプセル化や呼び出しが可能です。

8. フロントエンドに認証がある場合、バックエンドにも認証が必要ですか? #########必要! <p>前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全,无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!</p> <h3>九、来个小示例,加深一下印象</h3> <p>新建 <code>JurAuthController,复制以下代码

package com.pj.cases.use;

import java.util.List;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;

/**
 * Sa-Token 权限认证示例 
 * 
 * @author kong
 * @since 2022-10-13
 */
@RestController
@RequestMapping("/jur/")
public class JurAuthController {

	/*
	 * 前提1:首先调用登录接口进行登录,代码在 com.pj.cases.use.LoginAuthController 中有详细解释,此处不再赘述 
	 * 		---- http://localhost:8081/acc/doLogin?name=zhang&pwd=123456
	 * 
	 * 前提2:项目实现 StpInterface 接口,代码在  com.pj.satoken.StpInterfaceImpl
	 * 		Sa-Token 将从此实现类获取 每个账号拥有哪些权限。
	 * 
	 * 然后我们就可以使用以下示例中的代码进行鉴权了 
	 */
	
	// 查询权限   ---- http://localhost:8081/jur/getPermission
	@RequestMapping("getPermission")
	public SaResult getPermission() {
		// 查询权限信息 ,如果当前会话未登录,会返回一个空集合 
		List<String> permissionList = StpUtil.getPermissionList();
		System.out.println("当前登录账号拥有的所有权限:" + permissionList);
		
		// 查询角色信息 ,如果当前会话未登录,会返回一个空集合 
		List<String> roleList = StpUtil.getRoleList();
		System.out.println("当前登录账号拥有的所有角色:" + roleList);
		
		// 返回给前端 
		return SaResult.ok()
				.set("roleList", roleList)
				.set("permissionList", permissionList);
	}
	
	// 权限校验  ---- http://localhost:8081/jur/checkPermission
	@RequestMapping("checkPermission")
	public SaResult checkPermission() {
		
		// 判断:当前账号是否拥有一个权限,返回 true 或 false
		// 		如果当前账号未登录,则永远返回 false 
		StpUtil.hasPermission("user.add");
		StpUtil.hasPermissionAnd("user.add", "user.delete", "user.get");  // 指定多个,必须全部拥有才会返回 true 
		StpUtil.hasPermissionOr("user.add", "user.delete", "user.get");	 // 指定多个,只要拥有一个就会返回 true 
		
		// 校验:当前账号是否拥有一个权限,校验不通过时会抛出 `NotPermissionException` 异常 
		// 		如果当前账号未登录,则永远校验失败 
		StpUtil.checkPermission("user.add");
		StpUtil.checkPermissionAnd("user.add", "user.delete", "user.get");  // 指定多个,必须全部拥有才会校验通过 
		StpUtil.checkPermissionOr("user.add", "user.delete", "user.get");  // 指定多个,只要拥有一个就会校验通过 
		
		return SaResult.ok();
	}

	// 角色校验  ---- http://localhost:8081/jur/checkRole
	@RequestMapping("checkRole")
	public SaResult checkRole() {
		
		// 判断:当前账号是否拥有一个角色,返回 true 或 false
		// 		如果当前账号未登录,则永远返回 false 
		StpUtil.hasRole("admin");
		StpUtil.hasRoleAnd("admin", "ceo", "cfo");  // 指定多个,必须全部拥有才会返回 true 
		StpUtil.hasRoleOr("admin", "ceo", "cfo");	  // 指定多个,只要拥有一个就会返回 true 
		
		// 校验:当前账号是否拥有一个角色,校验不通过时会抛出 `NotRoleException` 异常 
		// 		如果当前账号未登录,则永远校验失败 
		StpUtil.checkRole("admin");
		StpUtil.checkRoleAnd("admin", "ceo", "cfo");  // 指定多个,必须全部拥有才会校验通过 
		StpUtil.checkRoleOr("admin", "ceo", "cfo");  // 指定多个,只要拥有一个就会校验通过 
		
		return SaResult.ok();
	}

	// 权限通配符  ---- http://localhost:8081/jur/wildcardPermission
	@RequestMapping("wildcardPermission")
	public SaResult wildcardPermission() {
		
		// 前提条件:在 StpInterface 实现类中,为账号返回了 "art.*" 泛权限
		StpUtil.hasPermission("art.add");  // 返回 true 
		StpUtil.hasPermission("art.delete");  // 返回 true 
		StpUtil.hasPermission("goods.add");  // 返回 false,因为前缀不符合  
		
		// * 符合可以出现在任意位置,比如权限码的开头,当账号拥有 "*.delete" 时  
		StpUtil.hasPermission("goods.add");        // false
		StpUtil.hasPermission("goods.delete");     // true
		StpUtil.hasPermission("art.delete");      // true
		
		// 也可以出现在权限码的中间,比如当账号拥有 "shop.*.user" 时  
		StpUtil.hasPermission("shop.add.user");  // true
		StpUtil.hasPermission("shop.delete.user");  // true
		StpUtil.hasPermission("shop.delete.goods");  // false,因为后缀不符合 

		// 注意点:
		// 1、上帝权限:当一个账号拥有 "*" 权限时,他可以验证通过任何权限码
		// 2、角色校验也可以加 * ,指定泛角色,例如: "*.admin",暂不赘述 
		
		return SaResult.ok();
	}
}

代码注释已针对每一步操作做出详细解释,大家可根据可参照注释中的访问链接进行逐步测试。

以上がSpringBoot が Sa-Token を使用してパーミッション認証を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。