如何在Angular 5的RxJS Http Get方法中封装Azure B2C认证令牌
在Angular 5中给RxJS Http请求附加Azure B2C令牌的封装方案
我来帮你搞定这个问题!既然你已经拿到了Azure B2C返回的认证令牌,要让Web API请求自动带上它,有几种不同的封装思路,适合不同的场景,我给你一一拆解:
方案1:在单个服务方法中手动添加令牌(快速实现)
这种方式适合只需要在少数几个请求里带令牌的场景,直接在你的ServerFlowTestService里修改即可:
首先,先导入需要的Headers和RequestOptions:
import { Http, Response, Headers, RequestOptions } from '@angular/http';
然后,把AuthenticationSandbox注入到服务的构造函数里(因为要获取令牌),再修改请求方法:
@Injectable() export class ServerFlowTestService{ private developmentBaseUrl: string = 'https://localhost:44370/'; // 注入AuthenticationSandbox constructor(private http: Http, private authSandbox: AuthenticationSandbox){} public getMessageFromWebAPI_T1():Observable<IMessageA[]> { // 获取Azure B2C令牌 const token = this.authSandbox.getToken(); // 创建请求头,添加Bearer认证令牌 const headers = new Headers({ 'Authorization': `Bearer ${token}` }); const requestOptions = new RequestOptions({ headers: headers }); return this.http.get(this.developmentBaseUrl+ '/app/analysis/GetMessage', requestOptions) .map((response:Response)=> <IMessageA[]>response.json()) } }
这样你的请求就会自动带上Authorization头了。
方案2:封装通用Http服务(避免重复代码)
如果你的应用里有很多请求都需要带令牌,重复写请求头太麻烦,不如封装一个基础Http服务,所有业务服务都基于它来调用:
先创建一个BaseHttpService:
import { Injectable } from '@angular/core'; import { Http, Headers, RequestOptions, Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import { AuthenticationSandbox } from './path-to-your-auth-sandbox'; // 替换成你的实际路径 @Injectable() export class BaseHttpService { private baseUrl: string = 'https://localhost:44370/'; constructor(private http: Http, private authSandbox: AuthenticationSandbox) {} // 封装带令牌的GET方法 public get(url: string): Observable<Response> { const token = this.authSandbox.getToken(); const headers = new Headers({ 'Authorization': `Bearer ${token}` }); const options = new RequestOptions({ headers: headers }); return this.http.get(this.baseUrl + url, options); } // 还可以封装POST、PUT等方法,逻辑和GET一致 }
然后你的业务服务就可以简化成这样:
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import{ IMessageA } from '../../../Interfaces/UnitTest/TestMessageA'; import { BaseHttpService } from './base-http.service'; // 替换成实际路径 @Injectable() export class ServerFlowTestService{ constructor(private baseHttp: BaseHttpService){} public getMessageFromWebAPI_T1():Observable<IMessageA[]> { return this.baseHttp.get('/app/analysis/GetMessage') .map((response:Response)=> <IMessageA[]>response.json()) } }
方案3:用HttpClient拦截器全局自动带令牌(最优雅)
Angular 5已经支持HttpClient(比旧的Http更强大),配合HttpInterceptor可以实现全局拦截所有请求,自动添加令牌,彻底告别重复代码:
第一步:切换到HttpClient
先在AppModule里导入HttpClientModule:
import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ ... HttpClientModule ] }) export class AppModule { }
第二步:创建认证拦截器
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { AuthenticationSandbox } from './path-to-your-auth-sandbox'; // 替换成实际路径 @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private authSandbox: AuthenticationSandbox) {} intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const token = this.authSandbox.getToken(); // 克隆请求并添加Authorization头(HttpRequest是不可变的,必须克隆修改) const authRequest = req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) }); // 继续处理修改后的请求 return next.handle(authRequest); } }
第三步:注册拦截器到AppModule
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { AuthInterceptor } from './auth.interceptor'; // 替换成实际路径 @NgModule({ ... providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true // 允许多个拦截器 } ] }) export class AppModule { }
第四步:简化你的业务服务
现在你的ServerFlowTestService可以直接用HttpClient,不用管令牌的事了:
import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import{ IMessageA } from '../../../Interfaces/UnitTest/TestMessageA'; @Injectable() export class ServerFlowTestService{ private developmentBaseUrl: string = 'https://localhost:44370/'; constructor(private http: HttpClient){} public getMessageFromWebAPI_T1():Observable<IMessageA[]> { // HttpClient支持直接指定返回类型,不用手动map了 return this.http.get<IMessageA[]>(this.developmentBaseUrl+ '/app/analysis/GetMessage') } }
一些注意事项
- 要确保令牌的有效性:如果令牌过期,你可能需要在拦截器或者获取令牌的逻辑里添加刷新令牌的处理,避免请求失败。
- 跨域配置:如果你的Angular应用和Web API不在同一个域名下,要确保Web API的CORS配置允许携带
Authorization头的请求。 - 空令牌处理:如果
getToken()返回空值,要添加判断,避免发送无效的Authorization头。
内容的提问来源于stack exchange,提问作者K.Z
相关产品推荐
相关产品推荐

