Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using Azure AD With ASP.NET Core

DZone's Guide to

Using Azure AD With ASP.NET Core

You can use cloud tools to spice up your ASP.NET Core app. Azure Active Directories can help with user authentication and to customize usernames for a nicer appearance.

· Cloud Zone
Free Resource

Linkerd, the open source service mesh for cloud native applications. Get the complete guide to using Linkerd and Kubernetes to build scalable, resilient applications.

To use Azure AD, a valid Microsoft Azure subscription is needed. That also goes for Azure AD services used by Office 365.

Using the Wizard for Azure AD Authentication

The simplest way to go about all this is adding Azure AD support to your application using Visual Studio. Visual Studio 2017 allows you to add Azure AD authentication for new applications. Hopefully, there will soon be support for adding Azure ADs to existing applications. As this is a how-to style post, I will start with a new default application.

The steps are simple:

  1. Create a new ASP.NET Core application
  2. Choose the  template
  3. Click on “Change Authentication”
  4. Select “Work or School Accounts”
  5. Choose the Azure AD you want to use
  6. Click “Ok”

ASP.NET Core: Connect to Azure AD

Visual Studio automatically adds a new configuration file with all the required configuration parameters, updates the Startup class of the web application, and adds an account controller that coordinates the authentication processes. If everything went well, then we have an application that supports Azure AD authentication and we can stop here.

Manually Connecting Your Application to an Azure Active Directory 

If we can’t use the nice wizard for some reason, then we can enable Azure AD support manually. This section is a short guide on to how to do it. Even if the Visual Studio wizard works, I suggest you go through the following sections of this blog post, as it gives you a better idea of how Azure AD support is actually implemented.

Add the following NuGet packages to a web application:

  • Microsoft.AspNetCore.Authentication.Cookies
  • Microsoft.AspNetCore.Authentication.OpenIdConnect

Add these settings to appsettings.json (this data can be found on the Azure Portal).


"Authentication": {
  "AzureAd": {
    "AADInstance": "https://login.microsoftonline.com/",
    "CallbackPath": "/signin-oidc",
    "ClientId": "your client id",
    "Domain": "your-domain.com",
    "TenantId": "your tenant id"
  }
}

We need to make a couple of changes to the Startup class, too. We'll start with the ConfigureServices() method. We add a call to AddAuthentication(), and then, to the Configure() method, add the call to UseOpenIdConnectAuthentication.


public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();       services.AddAuthentication(
        SharedOptions => SharedOptions.SignInScheme = 
                            CookieAuthenticationDefaults.AuthenticationScheme
    );
}
 
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();// ...
 
    app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
    {
        ClientId = Configuration["Authentication:AzureAd:ClientId"],
        Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
        CallbackPath = Configuration["Authentication:AzureAd:CallbackPath"]
    });       app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

We need an additional controller to coordinate authentication operations. The tooling – when it works – adds automatically a new account controller. Here is the code.


public class AccountController : Controller
{
    [HttpGet]
    public IActionResult SignIn()
    {
        return Challenge(
            new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectDefaults.AuthenticationScheme);
    }       [HttpGet]
    public IActionResult SignOut()
    {
        var callbackUrl = Url.Action(nameof(SignedOut), "Account", values: null, protocol: Request.Scheme);
        return SignOut(new AuthenticationProperties { RedirectUri = callbackUrl },
            CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme);
    }       [HttpGet]
    public IActionResult SignedOut()
    {
        if (HttpContext.User.Identity.IsAuthenticated)
        {
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }return View();
    }       [HttpGet]
    public IActionResult AccessDenied()
    {
        return View();
    }
}

It’s easy to see from code that there are two views we need to add. Here is the view for SignedOut action.


@{
    ViewData["Title"] = "Sign Out";
}
<h2>@ViewData["Title"].</h2>
<p class="text-success">You have successfully signed out.</p>

This is the view for the AccessDenied action.


@{
    ViewData["Title"] = "Access Denied";
}
 
<header>
    <h1 class="text-danger">Access Denied.</h1>
    <p class="text-danger">You do not have access to this resource.</p>
</header>

Now we are done with coding. It’s time to try out Azure AD authentication.

Trying Out Azure AD Authentication

When we run our application, we are redirected to the identity provider login page. In my case, it is the Microsoft Account login page. Take a look at the page title and notice my laziness.

Microsoft Account log-in page

After successful authentication, we are returned back to our application. Notice that my username is not an e-mail address or GUID or some long sequence of letters and numbers. It has a special format: <authentication provider>#<e-mail address>.

User name with provider

This username format is good for one thing – it is unique, and we can also use it when multiple active directories are available for application users.

What Data Do We Get From Azure AD?

The default username is not in a very user-friendly format, and the question is: What we can do to get something better there? Well, it’s a claim-based authentication identity, and we should look at the claims collection of the user. As claims contain sensitive information, I don’t show a screenshot here, but I show the code that displays claims.

To display the claims that the current claim identity has, we have to send claims from controller to view. Here is the Index action of my Home controller.


public IActionResult Index()
{
    var claims = ((ClaimsIdentity)User.Identity).Claims;
    return View(claims);
}

This code works only if we have identities of type ClaimsIdentity. With other authentication mechanisms, we may have other identity types. To support different identitites in same code base, we need a more common way to detect user attributes.

To show claims on the front page, we use the following table.


@model IEnumerable<System.Security.Claims.Claim>
@{
    ViewData["Title"] = "Home Page";
}
 
<div class="row">
    <div class="col-md-12">
        <table>
            <thead>
                <tr>
                    <th>Claim</th>
                    <th>Value</th>
                </tr>
            </thead>
            <tbody>
                @foreach(var claim in Model)
                {
                    <tr>
                        <td>@claim.Type</td>
                        <td>@claim.Value</td>
                    </tr>
                }
            </tbody>
        </table>
    </div>
</div>

Run the application, log in, and take a look at the table of claims. There is basic information about the user, like first name, last name, and e-mail address.

Displaying a Nice Username

We usually don't have the best default names to display to users when they are logged into our site. Let's look at the _LoginPartial view under the shared views folder.

@using System.Security.Principal   @if (User.Identity.IsAuthenticated)
{
    <ul class="nav navbar-nav navbar-right">
        <li class="navbar-text">Hello @User.Identity.Name!</li>
        <li><a asp-area="" asp-controller="Account" asp-action="SignOut">Sign Out</a></li>
    </ul>
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li><a asp-area="" asp-controller="Account" asp-action="Signin">Sign in</a></li>
    </ul>
}

We add some additional code here to make this view display the full name of user. As we saw from the claims table, there is a claim called name. This is the claim we will use.


@using System.Security.Principal
@using System.Security.Claims
@{ 
    var claims = ((ClaimsIdentity)User.Identity).Claims;
    var name = claims.FirstOrDefault(c => c.Type == "name")?.Value;
} @if (User.Identity.IsAuthenticated)
{
    <ul class="nav navbar-nav navbar-right">
        <li class="navbar-text">Hello @name</li>
        <li><a asp-area="" asp-controller="Account" asp-action="SignOut">Sign Out</a></li>
    </ul>
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li><a asp-area="" asp-controller="Account" asp-action="Signin">Sign in</a></li>
    </ul>
}

Instead of writing code to a partial view, we should use the view component and move this mark-up to some view of the view component. Here, I just wanted to show how to get the full name of current user.

Wrapping Up

Adding Azure AD support to ASP.NET Core applications is easy. It can be done using Visual Studio, but it also can be done manually. We needed a few additional configuration parameters, some lines of code, and a small change to login view. Although ASP.NET Core's default username doesn’t look nice, we were able to get user emails and full names from the claims collection from Azure AD.

Linkerd, the open source service mesh for cloud native applications. Get the complete guide to using Linkerd and Kubernetes to build scalable, resilient applications.

Topics:
azure active directory ,cloud ,asp.net core ,tutorial ,authentication

Published at DZone with permission of Gunnar Peipman, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}