国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - node.js - Nest.js 授權驗證的方法示例

Nest.js 授權驗證的方法示例

2022-01-21 16:55Jaxson Wang node.js

這篇文章主要介紹了Nest.js 授權驗證的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

0x0 前言

系統授權指的是登錄用戶執行操作過程,比如管理員可以對系統進行用戶操作、網站帖子管理操作,非管理員可以進行授權閱讀帖子等操作,所以實現需要對系統的授權需要身份驗證機制,下面來實現最基本的基于角色的訪問控制系統。

0x1 RBAC 實現

基于角色的訪問控制(RBAC)是圍繞角色的特權和定義的策略無關的訪問控制機制,首先創建個代表系統角色枚舉信息 role.enum.ts:

?
1
2
3
4
export enum Role {
 User = 'user',
 Admin = 'admin'
}

如果是更復雜的系統,推薦角色信息存儲到數據庫更好管理。

然后創建裝飾器和使用 @Roles() 來運行指定訪問所需要的資源角色,創建roles.decorator.ts:

?
1
2
3
4
5
import { SetMetadata } from '@nestjs/common'
import { Role } from './role.enum'
 
export const ROLES_KEY = 'roles'
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles)

上述創建一個名叫 @Roles() 的裝飾器,可以使用他來裝飾任何一個路由控制器,比如用戶創建:

?
1
2
3
4
5
@Post()
@Roles(Role.Admin)
create(@Body() createUserDto: CreateUserDto): Promise<UserEntity> {
 return this.userService.create(createUserDto)
}

最后創建一個 RolesGuard 類,它會實現將分配給當前用戶角色和當前路由控制器所需要角色進行比較,為了訪問路由角色(自定義元數據),將使用 Reflector 工具類,新建 roles.guard.ts:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'
import { Reflector } from '@nestjs/core'
 
import { Role } from './role.enum'
import { ROLES_KEY } from './roles.decorator'
 
@Injectable()
export class RolesGuard implements CanActivate {
 constructor(private reflector: Reflector) {}
 
 canActivate(context: ExecutionContext): boolean {
 const requireRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [context.getHandler(), context.getClass()])
 if (!requireRoles) {
  return true
 }
 const { user } = context.switchToHttp().getRequest()
 return requireRoles.some(role => user.roles?.includes(role))
 }
}

假設 request.user 包含 roles 屬性:

?
1
2
3
4
class User {
 // ...other properties
 roles: Role[]
}

然后 RolesGuard 在控制器全局注冊:

?
1
2
3
4
5
6
providers: [
 {
 provide: APP_GUARD,
 useClass: RolesGuard
 }
]

當某個用戶訪問超出角色范疇內的請求出現:

?
1
2
3
4
5
{
 "statusCode": 403,
 "message": "Forbidden resource",
 "error": "Forbidden"
}

0x2 基于聲明的授權

創建身份后,系統可以給身份分配一個或者多個聲明權限,表示告訴當前用戶可以做什么,而不是當前用戶是什么,在 Nest 系統里實現基于聲明授權,步驟和上面 RBAC 差不多,但有個區別是,需要比較權限,而不是判斷特定角色,每個用戶分配一組權限,比如定一個 @RequirePermissions() 裝飾器,然后訪問所需的權限屬性:

?
1
2
3
4
5
@Post()
@RequirePermissions(Permission.CREATE_USER)
create(@Body() createUserDto: CreateUserDto): Promise<UserEntity> {
 return this.userService.create(createUserDto)
}

Permission 表示類似 PRAC 中的 Role 枚舉,包含其中系統可訪問的權限組:

?
1
2
3
4
export enum Role {
 CREATE_USER = ['add', 'read', 'update', 'delete'],
 READ_USER = ['read']
}

0x3 集成 CASL

CASL 是一個同構授權庫,可以限制客戶端訪問的路由控制器資源,安裝依賴:

?
1
yarn add @casl/ability

下面使用最簡單的例子來實現 CASL 的機制,創建 User 和 Article 倆個實體類:

?
1
2
3
4
class User {
 id: number
 isAdmin: boolean
}

User 實體類倆個屬性,分別是用戶編號和是否具有管理員權限。

?
1
2
3
4
5
class Article {
 id: number
 isPublished: boolean
 authorId: string
}

Article 實體類有三個屬性,分別是文章編號和文章狀態(是否已經發布)以及撰寫文章的作者編號。

根據上面倆個最簡單的例子組成最簡單的功能:

  • 具有管理員權限的用戶可以管理所有實體(創建、讀取、更新和刪除)
  • 用戶對所有內容只有只讀訪問權限
  • 用戶可以更新自己撰寫的文章 authorId === userId
  • 已發布的文章無法刪除 article.isPublished === true

針對上面功能可以創建 Action 枚舉,來表示用戶對實體的操作:

?
1
2
3
4
5
6
7
export enum Action {
 Manage = 'manage',
 Create = 'create',
 Read = 'read',
 Update = 'update',
 Delete = 'delete',
}

manage 是 CASL 中的特殊關鍵字,表示可以進行任何操作。

實現功能需要二次封裝 CASL 庫,執行 nest-cli 進行創建需要業務:

?
1
2
nest g module casl
nest g class casl/casl-ability.factory

定義 CaslAbilityFactory 的 createForUser() 方法,來未用戶創建對象:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type Subjects = InferSubjects<typeof Article | typeof User> | 'all'
 
export type AppAbility = Ability<[Action, Subjects]>
 
@Injectable()
export class CaslAbilityFactory {
 createForUser(user: User) {
 const { can, cannot, build } = new AbilityBuilder<
  Ability<[Action, Subjects]>
 >(Ability as AbilityClass<AppAbility>);
 
 if (user.isAdmin) {
  can(Action.Manage, 'all') // 允許任何讀寫操作
 } else {
  can(Action.Read, 'all') // 只讀操作
 }
 
 can(Action.Update, Article, { authorId: user.id })
 cannot(Action.Delete, Article, { isPublished: true })
 
 return build({
  // 詳細:https://casl.js.org/v5/en/guide/subject-type-detection#use-classes-as-subject-types
  detectSubjectType: item => item.constructor as ExtractSubjectType<Subjects>
 })
 }
}

然后在 CaslModule 引入:

?
1
2
3
4
5
6
7
8
import { Module } from '@nestjs/common'
import { CaslAbilityFactory } from './casl-ability.factory'
 
@Module({
 providers: [CaslAbilityFactory],
 exports: [CaslAbilityFactory]
})
export class CaslModule {}

然后在任何業務引入 CaslModule 然后在構造函數注入就可以使用了:

?
1
2
3
4
5
6
constructor(private caslAbilityFactory: CaslAbilityFactory) {}
 
const ability = this.caslAbilityFactory.createForUser(user)
if (ability.can(Action.Read, 'all')) {
 // "user" 對所有內容可以讀寫
}

如果當前用戶是普通權限非管理員用戶,可以閱讀文章,但不能創建新的文章和刪除現有文章:

?
1
2
3
4
5
6
7
const user = new User()
user.isAdmin = false
 
const ability = this.caslAbilityFactory.createForUser(user)
ability.can(Action.Read, Article) // true
ability.can(Action.Delete, Article) // false
ability.can(Action.Create, Article) // false

這樣顯然有問題,當前用戶如果是文章的作者,應該可以對此進行操作:

?
1
2
3
4
5
6
7
8
9
10
11
const user = new User()
user.id = 1
 
const article = new Article()
article.authorId = user.id
 
const ability = this.caslAbilityFactory.createForUser(user)
ability.can(Action.Update, article) // true
 
article.authorId = 2
ability.can(Action.Update, article) // false

0x4 PoliceiesGuard

上述簡單的實現,但在復雜的系統中還是不滿足更復雜的需求,所以配合上一篇的身份驗證文章來進行擴展類級別授權策略模式,在原有的 CaslAbilityFactory 類進行擴展:

?
1
2
3
4
5
6
7
8
9
import { AppAbility } from '../casl/casl-ability.factory'
 
interface IPolicyHandler {
 handle(ability: AppAbility): boolean
}
 
type PolicyHandlerCallback = (ability: AppAbility) => boolean
 
export type PolicyHandler = IPolicyHandler | PolicyHandlerCallback

提供支持對象和函數對每個路由控制器進行策略檢查:IPolicyHandler 和 PolicyHandlerCallback。

然后創建一個 @CheckPolicies() 裝飾器來運行指定訪問特定資源策略:

?
1
2
export const CHECK_POLICIES_KEY = 'check_policy'
export const CheckPolicies = (...handlers: PolicyHandler[]) => SetMetadata(CHECK_POLICIES_KEY, handlers)

創建 PoliciesGuard 類來提取并且執行綁定路由控制器所有策略:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Injectable()
export class PoliciesGuard implements CanActivate {
 constructor(
 private reflector: Reflector,
 private caslAbilityFactory: CaslAbilityFactory,
 ) {}
 
 async canActivate(context: ExecutionContext): Promise<boolean> {
 const policyHandlers =
  this.reflector.get<PolicyHandler[]>(
  CHECK_POLICIES_KEY,
  context.getHandler()
  ) || []
 
 const { user } = context.switchToHttp().getRequest()
 const ability = this.caslAbilityFactory.createForUser(user)
 
 return policyHandlers.every((handler) =>
  this.execPolicyHandler(handler, ability)
 )
 }
 
 private execPolicyHandler(handler: PolicyHandler, ability: AppAbility) {
 if (typeof handler === 'function') {
  return handler(ability)
 }
 return handler.handle(ability)
 }
}

假設 request.user 包含用戶實例,policyHandlers 是通過裝飾器 @CheckPolicies() 分配,使用 aslAbilityFactory#create 構造 Ability 對象方法,來驗證用戶是否具有足夠的權限來執行特定的操作,然后將此對象傳遞給策略處理方法,該方法可以實現函數或者是類的實例 IPolicyHandler,并且公開 handle() 方法返回布爾值。

?
1
2
3
4
5
6
@Get()
@UseGuards(PoliciesGuard)
@CheckPolicies((ability: AppAbility) => ability.can(Action.Read, Article))
findAll() {
 return this.articlesService.findAll()
}

同樣可以定義 IPolicyHandler 接口類:

?
1
2
3
4
5
export class ReadArticlePolicyHandler implements IPolicyHandler {
 handle(ability: AppAbility) {
 return ability.can(Action.Read, Article)
 }
}

使用如下:

?
1
2
3
4
5
6
@Get()
@UseGuards(PoliciesGuard)
@CheckPolicies(new ReadArticlePolicyHandler())
findAll() {
 return this.articlesService.findAll()
}

到此這篇關于Nest.js 授權驗證的方法示例的文章就介紹到這了,更多相關Nest.js 授權驗證內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家! 

原文鏈接:https://iiong.com/nest-js-authorization-verification/

延伸 · 閱讀

精彩推薦
  • node.js在瀏覽器中,把 Vite 跑起來了!

    在瀏覽器中,把 Vite 跑起來了!

    大家好,我是 ssh,前幾天在推上沖浪的時候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運行起來了。這引起了我的興趣,如...

    前端從進階到入院9282022-01-11
  • node.jsrequire加載器實現原理的深入理解

    require加載器實現原理的深入理解

    這篇文章主要給大家介紹了關于require加載器實現原理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    隱冬8462022-03-03
  • node.jsnodejs中使用worker_threads來創建新的線程的方法

    nodejs中使用worker_threads來創建新的線程的方法

    這篇文章主要介紹了nodejs中使用worker_threads來創建新的線程的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友...

    flydean程序那些事8982022-01-06
  • node.jslinux服務器快速卸載安裝node環境(簡單上手)

    linux服務器快速卸載安裝node環境(簡單上手)

    這篇文章主要介紹了linux服務器快速卸載安裝node環境(簡單上手),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    mose-x8462022-01-22
  • node.js詳解node.js創建一個web服務器(Server)的詳細步驟

    詳解node.js創建一個web服務器(Server)的詳細步驟

    這篇文章主要介紹了詳解node.js創建一個web服務器(Server)的詳細步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    王佳斌8952021-12-31
  • node.jsk8s node節點重新加入master集群的實現

    k8s node節點重新加入master集群的實現

    這篇文章主要介紹了k8s node節點重新加入master集群的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    Scarborought13922022-01-22
  • node.jsNode.js 中如何收集和解析命令行參數

    Node.js 中如何收集和解析命令行參數

    這篇文章主要介紹了Node.js 中如何收集和解析命令行參數,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    descire8802021-12-28
  • node.jsNode.js ObjectWrap 的弱引用問題

    Node.js ObjectWrap 的弱引用問題

    最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。...

    編程雜技9852022-01-04
主站蜘蛛池模板: 欧美bbbxxx| 欧美国产精品一区二区三区 | av电影一区二区 | 男女视频网站 | 欧洲视频一区 | 国产女爽爽视频精品免费 | 久久一区 | 久久99精品久久久久久水蜜桃 | 久久久久久久一区 | 亚洲一区国产精品 | 国产精品国产精品国产专区不卡 | 欧洲精品久久久 | 一区二区三区 在线 | 午夜激情视频在线观看 | 亚洲久久 | 一级电影在线观看 | 亚洲精品成人在线 | 伊人久久综合 | 国产一级视频在线观看 | 欧美日一区 | 国产视频1区 | 韩日在线观看视频 | 在线视频一区二区三区 | 在线观看中文字幕av | 黄色片在线免费观看 | 欧美一区二区三区的 | 欧美日韩在线视频观看 | 欧美午夜精品久久久 | 精品久久久久久久久久久久 | 亚洲国产婷婷香蕉久久久久久99 | 成人福利电影 | 精品久久久久久久久久 | 国产av毛片 | av天天看 | 91久久夜色精品国产网站 | 中文字幕在线三区 | 中文字幕在线电影观看 | 黄色免费美女网站 | 黑人精品欧美一区二区蜜桃 | 国产亚洲精品美女久久久久久久久久 | www成人精品 |