简体   繁体   中英

Use AD B2C and MSAL v2 with Angular allowing selective unprotected Web API calls

My goal is to allow users to freely browse an Angular 11+ site, reading data called from a .NET Web API as they navigate. Only users who wish to post data or access particular features would need to sign up and sign in, using AD B2C identity services. Accordingly, controllers in the backend app service are marked with [Authorize] or [AllowAnonymous] as appropriate.

The site successfully supports browsing and posting for signed-in users, copying the approach from the AzureAD sample .

export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
  const protectedResourceMap = new Map<string, Array<string>>();
  protectedResourceMap.set(apiConfig.uri, apiConfig.scopes);
  return {
    interactionType: InteractionType.Redirect,
    protectedResourceMap
  };
}

However, using that approach, the Msal's httpInterceptor evidently fires for every database call, forcing a B2C signup/login event on all endpoints, defeating the effort to support anonymous browsing.

MSAL v1 apparently supported an unprotectedResource array, but that was deprecated for v2 . It also apparently supported the use of null patterns such as

const resourceMap: [string, string[]][] = [
  [`${apiBaseUrl}/health`, null],
  [`${apiBaseUrl}`, ['scope1', 'scope2']],
];

Since that v1 object has a different shape I tried it this way in v2, but to no avail

  const protectedResourceMap = new Map<string, Array<string>>();
  protectedResourceMap.set(apiConfig.uri + '/myreadabledata', []);
  protectedResourceMap.set(apiConfig.uri, apiConfig.scopes);

I've tried other approaches such as setting the protectedResourceMap exclusively for the controllers that require authorization. That failed as well.

  const protectedResourceMap = new Map<string, Array<string>>();
  protectedResourceMap.set(apiConfig.uri  + '/mycloseddata1' , apiConfig.scopes);
  protectedResourceMap.set(apiConfig.uri  + '/mycloseddata2' , apiConfig.scopes);

What is the correct way to achieve this?

I ran into this same issue of wanting some api routes to be anonymous and not trigger a redirect to login. Managed to come across this link .

It looks like you were really close with what you tried. Translating what I did I believe you can use the following

const protectedResourceMap = new Map<string, Array<string>>();
protectedResourceMap.set(apiConfig.uri + '/myreadabledata/*', null);
protectedResourceMap.set(apiConfig.uri, apiConfig.scopes);

From reading the code the trick looks to be to put your unprotected path(s) first and have it return a scope of null .

I'm running 2.0.0-beta.5 and this works for me when calling GET uri/myreadabledata/{id}

I fixed it by wrapping the MsalInterceptor in a custom interceptor. Currently it only applies the MsalInterceptor once a user is logged in as seen below:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
import { MsalInterceptor, MsalService } from '@azure/msal-angular';

@Injectable()
export class RequestInterceptor implements HttpInterceptor {
  constructor(private authService: MsalService, private msalInterceptor: MsalInterceptor) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    const accounts = this.authService.instance.getAllAccounts();
    const isLoggedIn = accounts.length > 0;

    if (isLoggedIn) {
      return this.msalInterceptor.intercept(request, next);
    } else {
      return next.handle(request);
    }
  }
}

One could also opt for a different kind of filter (instead of just looking if the user is logged in). For example, a separate protected resource map could be used in the custom interceptor. This way, one could still mark resources that are protected and instantiate an automatic login redirect.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM