Angular: 为Angular SPA程序添加Authorization支持
admin
2024-04-04 02:42:22
0

本篇详细描述怎么为Angular SPA程序添加Authorization的全记录。相对应的,本篇中使用了Identity Server (.Net Core开源项目)作为Identity Provider。

本文目录

  • AccessToken和Refresh Token
  • 安装依赖
  • 更新Angular SPA程序
    • 创建Unauthorized的Module和Component
    • 添加Angular程序的路由
    • 添加路由保护
    • 登录及登出操作
    • 使用Access Token

AccessToken和Refresh Token

权限控制无所不在,基于OAuth, OpenID这些解决方案在今时今日的开发中几乎是必不可少的。

这里只强调下Access Token和Refresh Token的关联与区别:

  • Access Token的生命周期通常是比较短暂。譬如Identity Server设置一般设置为3600秒,即一个小时就会过期;
  • Refresh Token。显然每个小时就要终端客户重输密码来登录不是个很好的设计,所以Refresh Token提出来用以简化登录次数。通常Refresh Token默认比较长。Identity Server中一般设置为30天。

那么Access Token怎么跟Refresh Token协同工作呢?一般来说,整个

  • Client进行登录,Server会同时发放Access Token和Refresh token;通常Client会保存住Refresh Token;
  • 当Client察觉到Access Token过期时,它会Refresh token要求刷新Access token;
  • Server会根据Refresh Token的有效性并下发最新的Access Token;
  • 重复上述两步(这两步均无客户干预),直至Refresh Token也失效;
  • Refresh Token也失效时,重新登录。

由于Refresh Token这个特效,在开发库中,其也被称为Offline Access。

安装依赖

如果是Angular CLI创建的应用程序,添加:

ng add angular-auth-oidc-client

当然也可以使用NPM/YARN来安装。

当开始执行时,首先要求确认:

ℹ Using package manager: npm
✔ Found compatible package version: angular-auth-oidc-client@14.1.5.
✔ Package information loaded.The package angular-auth-oidc-client@14.1.5 will be installed and executed.
Would you like to proceed? (Y/n) 

当选择Y之后,会进行安装,并要求输入一些必要信息。下列中的(XXXX)是项目特定信息,需要按照项目的实际填写。

✔ Package successfully installed.
? What flow to use? OIDC Code Flow PKCE using refresh tokens
? Please enter your authority URL or Azure tenant id or Http config URL (XXXX)🔎 Running checks...✅️ Project found, working with 'myproject'✅️ Added "angular-auth-oidc-client" 14.1.5🔍 Installing packages...✅️ Installed✅️ 'src/app/auth/auth-config.module.ts' will be created✅️ 'AuthConfigModule' is imported in 'src/app/app.module.ts'✅️ All imports done, please add the 'RouterModule' as well if you don't have it imported yet.✅️ No silent-renew entry in assets array needed✅️ No 'silent-renew.html' needed
CREATE src/app/auth/auth-config.module.ts (703 bytes)
UPDATE package.json (2281 bytes)
UPDATE src/app/app.module.ts (3951 bytes)

这时,项目中多了一个src\auth的文件夹,其中只有一个Module。

@NgModule({imports: [AuthModule.forRoot({config: {authority: 'XXXX.com',redirectUrl: window.location.origin,postLogoutRedirectUri: window.location.origin,clientId: 'please-enter-clientId',scope: 'please-enter-scopes', // 'openid profile offline_access ' + your scopesresponseType: 'code',silentRenew: true,useRefreshToken: true,renewTimeBeforeTokenExpiresInSeconds: 30,}})],exports: [AuthModule],
})
export class AuthConfigModule {}

其中有些信息需要更新:scopeclientId等。

如果需要silent renew(自动更新Access Token),需要在scope中加上offline_access,并且在Identity Provider也设置为Allow Offlien Access。

以Identity Server 6为例:

    new Client{ClientName = "My App",ClientId = "myangularapp",AllowedGrantTypes = GrantTypes.Code,RequireClientSecret = false,RequirePkce = true,AllowAccessTokensViaBrowser = true,AllowOfflineAccess = true, // For refresh token}

更新Angular SPA程序

创建Unauthorized的Module和Component

Unauthorized的Module和Component用来向客户显示错误信息。

首先创建Module:

ng g m pages\Unauthorized --routing

然后是Component:

ng g c pages\Unauthorized -m pages\unauthorized

可以在pages\unauthorized\unauthorized.html中填充显示给终端客户的权限检查失败的信息。

譬如:

You are not unauthorized to access

更新Unauthorized Module中的路由(即文件unauthorized-routing.module.ts)来添加标准跳转:

const routes: Routes = [{path: '', component: UnauthorizedComponent
}];

添加Angular程序的路由

在Angular程序中添加路由,用来支持跳转到上述刚刚创建的unauthorized的页面。

通常,在app-routing.module.ts中添加路由项:

  { path: 'unauthorized', loadChildren: () => import('./pages/unauthorized/unauthorized.module').then(m => m.UnauthorizedModule) },

这时,在Angular SPA程序中的路由unauthorized已经添加完成。

添加路由保护

对需要Authorization的路由添加保护:

@Injectable({providedIn: 'root'
})
export class AuthGuardService implements CanActivate {constructor(private authService: OidcSecurityService, private router: Router) { }canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise {const url: string = state.url;return firstValueFrom(this.checkLogin(url));}checkLogin(url: string): Observable {return this.authService.isAuthenticated().pipe(map((rst: boolean) => {if (!rst) {this.authService.authorize();}return true;}));}
}

更新路由项:

  {path: 'protected-path',canActivate: [AuthGuardService],loadChildren: () => import('./pages/protected-path/protected-path.module').then(m => m.ProtectedPathModule),},

登录及登出操作

登录(Login)和登出(Logout)操作一般放在主Component中进行,即,通常都是app.component.ts中:

在构造函数中添加:

    constructor(public oidcSecurityService: OidcSecurityService,) {// Other codes...}

添加登录函数:

  public onLogon(): void {this.oidcSecurityService.authorize();}

登出函数:

  public onLogon(): void {this.oidcSecurityService.logoffAndRevokeTokens().subscribe();}

通常在ngOnInit中添加相应Subscription来接受Logon的回调:

  ngOnInit(): void {this.oidcSecurityService.checkAuth().subscribe(({ isAuthenticated, userData, accessToken, idToken }) => {if (isAuthenticated) {        this.oidcSecurityService.getUserData().subscribe(val => {this.currentUser = `${val.name}(${val.sub})`;});}});}

使用Access Token

如果申请到的Access Token是用来访问被保护的API,那么Access Token就需要传给对应的API(authService也是注入在Constructor中的OidcSecurityService的实例):

    return this.authService.isAuthenticated().pipe(mergeMap(islogin => {if (!islogin) {return of({totalCount: 0, items: []});}let headers: HttpHeaders = new HttpHeaders();headers = headers.append(this.contentType, this.appJson).append(this.strAccept, this.appJson);let params: HttpParams = new HttpParams();params = params.append('$top', top.toString());params = params.append('$skip', skip.toString());return this.authService.getAccessToken().pipe(mergeMap(token => {headers = headers.append('Authorization', 'Bearer ' + token);return this.http.get(apiurl, {headers,params,}).pipe(map(response => {// Success received the responsereturn {items};}),catchError((error: HttpErrorResponse) => throwError(() => new Error(error.statusText + '; ' + error.error + '; ' + error.message))));}));  }));

相关内容

热门资讯

求姓名藏头诗一首,给女朋友的,... 求姓名藏头诗一首,给女朋友的,她叫刘树红要古体诗七言那种,意境要美要押韵你乃本是天生仙,与我相聚下凡...
希望大家给我介绍几本关于人生经... 希望大家给我介绍几本关于人生经历方面的好书,谢谢了!!!《让方向更清晰!!》作者:爱琳·C卡瑟拉《《...
海贼王萨博在德雷斯罗萨回忆里得... 海贼王萨博在德雷斯罗萨回忆里得知艾斯的死讯是在哪集?没有具体说明在哪集,那只是个回忆片段而已。动漫里...
武林外传里佟掌柜儿时的好友说的... 武林外传里佟掌柜儿时的好友说的是什么地方的方言?一楼的,是陕西话那为什么和佟掌柜说的不一样?是陕西话...
用英语以春节为题的手抄报 春节... 用英语以春节为题的手抄报 春节英语手抄报小学生春节英语手抄报教程关于春节的英语手抄报怎么画春节英语手...
大学生研发校徽月饼是什么样子的... 大学生研发校徽月饼是什么样子的?大学生研发“校徽月饼”走红 原料取材学校培育作物。陕西大学生研发“彩...
《潜伏》中,晚秋是个什么样的人... 《潜伏》中,晚秋是个什么样的人?结局如何晚秋有着悲惨的命运,一直深爱着孙红蕾,最后孙红蕾在香港执行任...
我爱上了我的小学女同桌,我13... 我爱上了我的小学女同桌,我13岁13岁 好小的年龄呀!暗恋两年也不错,主要是你们太小了,现在你们懂得...
TVB出过一个动画是在讲一些章... TVB出过一个动画是在讲一些章鱼小丸子的故事的叫什么?【是在一个类似放学ICY的节目播的】章鱼小超人...
谁有周建龙版的 有声小说 盗墓... 谁有周建龙版的 有声小说 盗墓笔记 7 8 部 分享下 谢谢盗吧首页吧规+资源,甭找了,就没这东西周...
当你一个人在深夜发呆的时候 会... 当你一个人在深夜发呆的时候 会听什么歌?推荐几首好听的额你喜欢悲伤的还是节奏性强的啊?
搞笑一家人剧情 搞笑一家人剧情尤美喜欢谁?我觉得才开始尤美喜欢允浩,允浩也喜欢尤美,只是尤美误会是她爸爸杀了开成嫂的...
跪求好听的歌! 跪求好听的歌!英文歌 中文歌都要 重在好听多来点啊下个,路口,见圣诞结 爱似水仙你若...
我只会打字,对电脑编程不懂怎么... 我只会打字,对电脑编程不懂怎么办?这没有其他的办法,只有深造你要学习吗?
百听不厌的50首经典老歌推荐 百听不厌的50首经典老歌推荐百听不厌的50首经典老歌推荐:1、后来2、光辉岁月3、鬼迷心窍4、大海5...
关于防溺水的手抄报,自己防溺水... 关于防溺水的手抄报,自己防溺水的卡通图片,各位亲,急用啊!
怪物猎人XX烬灭刃斩龙怎么打 怪物猎人XX烬灭刃斩龙怎么打你问怎么打没意义,各人打法不一样,比如咬尾巴大回旋人家直接滚过去输出,你...
工笔画淡蓝色怎么调 工笔画淡蓝色怎么调哪个?淡蓝色,画什么的有好多种蓝色,你要哪个 你要往哪上色白色加里面的任意一种蓝色...
缅甸富人区女孩,个个貌美有钱,... 缅甸富人区女孩,个个貌美有钱,为什么很难嫁出去?缅甸富人区女孩,个个貌美有钱,很难嫁出去有两个原因。...
我的家园写一篇童话作文 我的家园写一篇童话作文你可以将时间写成魔法师,把你家园写成童话王国,