I would like to create an ASP.NET Core 2.0 application that uses Azure Active Directory as the identity provider (for authentication) but ASP.NET Core Identity for authorization (e.g. using controller attributes like '[Authorize(Roles = "Admin")]'). In the solution, I expect the local Identity database table AspNetUserLogins to hold references to the Azure Active Directory identities
I think the solution would involve claim transformation to decorate the authenticated user with roles fetched from ASP.NET Core Identity.
My problems:
- I can get Azure Active Directory authentication working from the Visual Studio Solution template, however I can't figure out how to then add and configure ASP.NET Core Identity (e.g. services.AddIdentity() etc. somewhere in Startup.ConfigureServices())
- I'd like to know where the correct hook is to do the claim transformation. (e.g. OpenIdConnectEvents.OnTokenValidated or maybe an AccountController method)
Steps to reproduce my baseline...
In portal.azure.com...
- Azure Active Directory > App Registrations > New Application Registration (you can delete this later)
- Give the application a name and set it to 'Wep app / API'
- Set 'Sign-on URL' to something arbitrary like 'https://blabla'
- Go to the newly created app registration and copy the 'Application ID'
Create ASP.NET Core 2.0 project using Visual Studio 2017 15.4.2...
- ASP.NET Core Web Application
- .NET Framework, ASP.NET Core 2.0, 'Web Application'
- Change Authentication > 'work or school accounts'
- select 'cloud - single organization'
- enter your domain 'something.onmicrosoft.com' (I guess)
- click through the wizard to create the project
- edit appsettings.json and change the 'ClientId' to the 'Application ID' (copied from portal.azure.com)
- copy the value set for 'CallbackPath' (e.g. '/signin-oidc')
- go to project properties > Debug > and copy the IIS Express https url (e.g. 'https://localhost:44366/')
- switch back to the new App Registration in portal.azure.com
- 'Reply URLs' > Add a new reply URL from the concatenation of the two pieces of information above (e.g. 'https://localhost:44366/signin-oidc')
- click 'Save'
- Run the project in Visual Studio
- Login using your Azure Active Directory account (you will be asked to consent to the permissions required by the app)
- You should then end up at the ASP.NET Core demo page
I'm less certain from here...
(I borrowed code from the template-generated solution with 'authentication options' set to 'Individual User Accounts' > 'Store user accounts in-app'.)
- Add nuget package Microsoft.AspNetCore.Identity.EntityFrameworkCore (I had to upgrade Microsoft.AspNetCore.Authentication.Cookies from 2.0.0 to 2.0.1 first though for it to install)
- Add nuget package Microsoft.EntityFrameworkCore.SqlServer
Add the following classes
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext(DbContextOptions<AspNetCoreIdentity.Data.ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); } } public class ApplicationUser : IdentityUser { }
Add the following at the beginning of Startup.ConfigureServices()
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();
Add connection string to appsettings.json (assumes default SQL Server instance on localhost and identity database named 'AspNetCoreIdentity')
"ConnectionStrings": { "DefaultConnection": "Data Source=.\\;Initial Catalog=AspNetCoreIdentity;Integrated Security=True;MultipleActiveResultSets=True" }
Now when I run the app again, I end up in a redirect loop which I think runs between my app and Azure Active Directory sign on. Tracing shows...
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed for user: (null).
Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker: Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
I then tried adding methods to AccountController (Login, ExternalLogin) in the hope that I could hit a breakpoint, but now I'm really stuck.
other references...
- http://www.blinkingcaret.com/2016/11/30/asp-net-identity-core-from-scratch
- http://www.blinkingcaret.com/2017/05/03/external-login-providers-in-asp-net-core
- https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity
- asp.net core identity extract and save external login tokens and add claims to local identity
- ASP.NET Identity: Update external claims after authorization
- SignInManager,what it is and how,when to use?