在 Dynamics 365 资源中为 Auth/Authz 使用 MSAL 以访问外部 Azure API
Using MSAL for Auth/Authz in a Dynamics 365 resource to access external Azure API
我有一个 Angular 应用程序部署为 D365 中的 Web 资源,使用 MSAL 库 Auth/Auhtz 访问 Azure 中托管的外部 Web API。当 运行 Dynamics 之外的应用程序一切正常时,MSAL 库检索访问令牌并将其附加到对 Azure Web 的授权请求 API。当我将文件作为 Web 资源部署到 Dynamics 时会出现问题。下面是我的应用模块中的错误和 MSAL 配置。
MSAL 日志记录:2020 年 10 月 16 日,星期五 13:14:53 GMT:943d26e4-f4b2-48b7-a882-f1a835959476-1.4.0-Error 获取范围令牌时出错:https ://...azurewebsites.net/default ClientAuthError:需要用户登录。对于静默调用,请求必须包含 sid 或 login_hint
MsalModule.forRoot({
auth: {
clientId: config.auth.clientId,
authority: config.auth.authority,
redirectUri: config.auth.redirectUri
},
cache: {
cacheLocation: <CacheLocation>config.cache.cacheLocation,
storeAuthStateInCookie: isIE, // set to true for IE 11
},
},
{
popUp: !isIE,
consentScopes: config.scopes.graphScopes,
unprotectedResources: [],
protectedResourceMap: [
[config.baseuri, [config.baseuri.concat('/', config.scopes.gatewayScopes)]],
[config.protectedResources.graphEndpoint, config.scopes.graphScopes]
],
extraQueryParameters: {},
})
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true
}
]
我已经苦苦挣扎了2天了,一点运气都没有。
求助!!!
试试下面的自定义拦截器。为此,您需要启用 sid optional claim.
@Injectable()
export class CustomInterceptor implements HttpInterceptor {
constructor(private auth: MsalService, private broadcastService: BroadcastService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const scopes = this.auth.getScopesForEndpoint(req.url);
this.auth.getLogger().verbose("Url: " + req.url + " maps to scopes: " + scopes);
// If there are no scopes set for this request, do nothing.
if (!scopes) {
return next.handle(req);
}
let token: string;
// Acquire a token for this request, and attach as proper auth header.
const obs = from(
this.auth.acquireTokenSilent({ scopes, sid: this.auth.getAccount().idTokenClaims["sid"] })
.then((response: AuthResponse) => {
token = response.tokenType === ServerHashParamKeys.ID_TOKEN ? response.idToken.rawIdToken : response.accessToken;
const authHeader = `Bearer ${token}`;
return req.clone({
setHeaders: {
Authorization: authHeader,
}
});
})
)
.pipe(
mergeMap((nextReq: HttpRequest<any>) => next.handle(nextReq)),
tap(
event => { }, // tslint:disable-line
err => {
if (err instanceof HttpErrorResponse && err.status === 401) {
this.auth.clearCacheForScope(token);
this.broadcastService.broadcast("msal:notAuthorized", err.message);
}
}
)
);
return obs as Observable<HttpEvent<any>>;
}
}
我有一个 Angular 应用程序部署为 D365 中的 Web 资源,使用 MSAL 库 Auth/Auhtz 访问 Azure 中托管的外部 Web API。当 运行 Dynamics 之外的应用程序一切正常时,MSAL 库检索访问令牌并将其附加到对 Azure Web 的授权请求 API。当我将文件作为 Web 资源部署到 Dynamics 时会出现问题。下面是我的应用模块中的错误和 MSAL 配置。
MSAL 日志记录:2020 年 10 月 16 日,星期五 13:14:53 GMT:943d26e4-f4b2-48b7-a882-f1a835959476-1.4.0-Error 获取范围令牌时出错:https ://...azurewebsites.net/default ClientAuthError:需要用户登录。对于静默调用,请求必须包含 sid 或 login_hint
MsalModule.forRoot({
auth: {
clientId: config.auth.clientId,
authority: config.auth.authority,
redirectUri: config.auth.redirectUri
},
cache: {
cacheLocation: <CacheLocation>config.cache.cacheLocation,
storeAuthStateInCookie: isIE, // set to true for IE 11
},
},
{
popUp: !isIE,
consentScopes: config.scopes.graphScopes,
unprotectedResources: [],
protectedResourceMap: [
[config.baseuri, [config.baseuri.concat('/', config.scopes.gatewayScopes)]],
[config.protectedResources.graphEndpoint, config.scopes.graphScopes]
],
extraQueryParameters: {},
})
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true
}
]
我已经苦苦挣扎了2天了,一点运气都没有。
求助!!!
试试下面的自定义拦截器。为此,您需要启用 sid optional claim.
@Injectable()
export class CustomInterceptor implements HttpInterceptor {
constructor(private auth: MsalService, private broadcastService: BroadcastService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const scopes = this.auth.getScopesForEndpoint(req.url);
this.auth.getLogger().verbose("Url: " + req.url + " maps to scopes: " + scopes);
// If there are no scopes set for this request, do nothing.
if (!scopes) {
return next.handle(req);
}
let token: string;
// Acquire a token for this request, and attach as proper auth header.
const obs = from(
this.auth.acquireTokenSilent({ scopes, sid: this.auth.getAccount().idTokenClaims["sid"] })
.then((response: AuthResponse) => {
token = response.tokenType === ServerHashParamKeys.ID_TOKEN ? response.idToken.rawIdToken : response.accessToken;
const authHeader = `Bearer ${token}`;
return req.clone({
setHeaders: {
Authorization: authHeader,
}
});
})
)
.pipe(
mergeMap((nextReq: HttpRequest<any>) => next.handle(nextReq)),
tap(
event => { }, // tslint:disable-line
err => {
if (err instanceof HttpErrorResponse && err.status === 401) {
this.auth.clearCacheForScope(token);
this.broadcastService.broadcast("msal:notAuthorized", err.message);
}
}
)
);
return obs as Observable<HttpEvent<any>>;
}
}