Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asp net core project MVC controllers using Cookie Authentication and api end points using Bearer

I am working on a project using ASP .net CORE, where we have Angular 2 and MVC and API, need to be protected by Azure AD.

Home/Index MVC controller will start the Angular 2 SPA and Home/Index need to be protected by cookie authentication. I manage to get the token using the OpenIdConnectAuthentication - OnAuthorizationCodeReceived event.

I need to protect the MVC controllers (there are few more controllers apart from Home/Index) using Cookie based Authentication and API using Bearer Authentication, I can get the token from API to Angular then use that token for each subsequent call to API.

In the near future there will be mobile apps calling the same API end points, using Bearer tokens.

This was my starting point: https://learn.microsoft.com/en-us/azure/active-directory/active-directory-appmodel-v2-overview

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc().AddJsonOptions(config => { config.SerializerSettings.ContractResolver = new DefaultContractResolver(); });

   services.AddAuthentication(sharedOptions => sharedOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
   app.UseCookieAuthentication(new CookieAuthenticationOptions());

   Authority = $"https://login.microsoftonline.com/AAAAA}";
   ClientId = "BBBB";
   ClientSecret = "CCCC";
   Audience = "https://localhost:44333/";

   app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
   {
      ClientId = ClientId,
      Authority = Authority,
      PostLogoutRedirectUri = Audience,
      ResponseType = OpenIdConnectResponseType.CodeIdToken,
      GetClaimsFromUserInfoEndpoint = false,
      Events = new OpenIdConnectEvents
      {
        OnTokenValidated = TokenValidated,
        OnRemoteFailure = OnAuthenticationFailed,
        OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
      }
   });

     app.UseMvc(....);
}

Question:

How can I configure the API to use just "Bearer" auth and MVC to use Cookies?

Update

Hi Adem Thank you for your reply.

I never tired 1st option, will give it a go now. but I have tired 2nd option earlier, and just tired it as below.

Added this below app.UseOpenIdConnectAuthentication(...

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
   Authority = "https://login.microsoftonline.com/AAAA",
   Audience = "https://BBB.onmicrosoft.com/CCCC"
});

For API Controller [Authorize(ActiveAuthenticationSchemes = "Bearer")]

For MVC Controller [Authorize(ActiveAuthenticationSchemes = "Cookies")]

When it hits my Home Controller it get this error Specified method is not supported.

this Stack Trace at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler1.HandleSignInAsync(SignInContext context) at Microsoft.AspNetCore.Authentication.AuthenticationHandler1.d__66.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Http.Authentication.Internal.DefaultAuthenticationManager.d__14.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler1.<HandleRemoteCallbackAsync>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler1.d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.d__15.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware1.<Invoke>d__18.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware1.d__18.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.d__6.MoveNext()

Update 2: I have tired configuring 2 different auth for APIand MVC like below

app.UseWhen(context => 
  context.Request.Path.StartsWithSegments("/api"), appBuilder =>
  {
    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
      Authority = Authority,
      Audience = Configuration["Authentication:AzureAd:Audience"]
    });
  });
app.UseWhen(context => 
  !context.Request.Path.StartsWithSegments("/api"), appBuilder =>
  {
    app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
    {
      ClientId = ClientId,
      Authority = Authority,
      PostLogoutRedirectUri = Audience,
      ResponseType = OpenIdConnectResponseType.CodeIdToken,
      GetClaimsFromUserInfoEndpoint = false,
      Events = new OpenIdConnectEvents
      {
        OnTokenValidated = TokenValidated,
        OnRemoteFailure = OnAuthenticationFailed,
        OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
      }
  });
});

But API still seem to be using the cookie auth. I could still see the the request has cookies in the request.

Thank you Asanka

like image 831
NeroIsNoHero Avatar asked Dec 13 '16 03:12

NeroIsNoHero


1 Answers

One way is to branch application like this:

app.UseWhen(context => <isApiRequest>, appBuilder =>
{
    appBuilder.UseJwtBearerAuthentication(); 
} 
app.UseWhen(context => <isNotApiRequest>, appBuilder =>
{
    appBuilder.UseCookieAuthentication();
} 

note: you could branch your api with "/api" prefix, in this case <isApiRequest> would be context.Request.Path.StartsWithSegment("/api")

Another way is to use AuthenticationScheme:

app.UseCookieAuthentication(//....);
app.UseJwtBearerAuthentication(//...);

Then in api action use Bearer scheme:

[Authoırize(ActiveAuthenticationSchemes = "Bearer")]
public IActionResult ApiAction(){}

For mvc actions use Cookies scheme

[Authoırize(ActiveAuthenticationSchemes = "Cookies")]
public IActionResult MvcAction(){}
like image 102
adem caglin Avatar answered Oct 21 '22 10:10

adem caglin