Implement authentication using Azure AD (Azure Identity) for ASP.NET MVC app

144 Views Asked by At

I about to host an existing ASP.NET MVC app running on .NET 4.8 in Azure. I want to implement authentication using Azure AD (Azure Identity).

I am looking for some quickstart or walk-through but can't find what I used to find just a year ago. Can someone help me steps so I can enable my app to use Azure AD authentication?

Thanks

1

There are 1 best solutions below

0
Aslesha Kantamsetti On

I used the code below to implement AzureAD for ASP.NET MVC .NET 4.8 app.

I created an Account Controller in the controller folder, as shown below.

AccountController:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Microsoft.Owin.Security;

namespace MvcWithAzureAd123.Controllers
{
    public class AccountController : Controller
    {
        public void SignIn()
        {
            if (!Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" },
                    OpenIdConnectAuthenticationDefaults.AuthenticationType);
            }
        }
        public void SignOut()
        {
            string callbackUrl1 = Url.Action("SignOutCallback", "Account", routeValues: null, protocol: Request.Url.Scheme);
            HttpContext.GetOwinContext().Authentication.SignOut(
                new AuthenticationProperties { RedirectUri = callbackUrl },
                OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
        }
        public ActionResult SignOutCallback()
        {
            if (Request.IsAuthenticated)
            {            
                return RedirectToAction("Index", "Home");
            }
            return View();
        }
    }
}

I added the Startup.Auth.cs class to my App_Start folder.

App_Start/Startup.Auth.cs:

using System;
using System.Configuration;
using System.Security.Claims;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;

namespace MvcWithAzureAd123
{
    public partial class Startup
    {
        private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
        private static string aadInstance = EnsureTrailingSlash(ConfigurationManager.AppSettings["ida:AADInstance"]);
        private static string tenantId = ConfigurationManager.AppSettings["ida:TenantId"];
        private static string postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
        private static string authority = aadInstance + tenantId + "/v2.0";
        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = clientId,
                    Authority = authority,
                    PostLogoutRedirectUri = postLogoutRedirectUri,
                    Notifications = new OpenIdConnectAuthenticationNotifications()
                    {
                        SecurityTokenValidated = (context) =>
                        {
                            string name = context.AuthenticationTicket.Identity.FindFirst("preferred_username").Value;
                            context.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Name, name, string.Empty));
                            return System.Threading.Tasks.Task.FromResult(0);
                        }
                    }
                });
        }
        private static string EnsureTrailingSlash(string value)
        {
            if (value == null)
            {
                value = string.Empty;
            }
            if (!value.EndsWith("/", StringComparison.Ordinal))
            {
                return value + "/";
            }
            return value;
        }
    }
}

I created an app registration in my Azure account, as shown below:

enter image description here

I added ClientId, TenantId, and dependentAssembly to the web.config, as shown below.

web.config:

<appSettings>
  <add key="webpages:Version" value="3.0.0.0" />
  <add key="webpages:Enabled" value="false" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  <add key="ida:ClientId" value="<ClientId>" />
  <add key="ida:AADInstance" value="https://login.microsoftonline.com/" />
  <add key="ida:Domain" value="microsoft.onmicrosoft.com" />
  <add key="ida:TenantId" value="<TenanatId>" />
  <add key="ida:PostLogoutRedirectUri" value="https://<URL>/signin-oidc" />
</appSettings>

 <runtime>
   <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
        <assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.5.0.0" newVersion="5.5.0.0" />
    </dependentAssembly>
    <dependentAssembly>
        <assemblyIdentity name="Microsoft.IdentityModel.Protocols.OpenIdConnect" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.5.0.0" newVersion="5.5.0.0" />
    </dependentAssembly>
    <dependentAssembly>
        <assemblyIdentity name="Microsoft.IdentityModel.Protocols" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.5.0.0" newVersion="5.5.0.0" />
    </dependentAssembly>
    <dependentAssembly>
        <assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.5.0.0" newVersion="5.5.0.0" />
    </dependentAssembly>
    <dependentAssembly>
        <assemblyIdentity name="Microsoft.IdentityModel.Protocol.Extensions" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-1.0.40306.1554" newVersion="1.0.40306.1554" />
    </dependentAssembly>
    <---------Other dependentAssembly-------->
  </runtime>

I added a Startup.cs class to the root directory.

Startup.cs:

using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
namespace MvcWithAzureAd123
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}

Then, I implemented the _loginPartial.cshtml view in the Shared folder, as shown below.

Shared/_LoginPartial.cshtml:

@if (Request.IsAuthenticated)
{
    <text>
        <ul class="navbar-nav navbar-right">
            <li class="navbar-text">
                Hello, @User.Identity.Name!
            </li>
            <li>
                @Html.ActionLink("Sign out", "SignOut", "Account", new { area = "" }, new { @class = "nav-link" })
            </li>
        </ul>
    </text>
}
else
{
    <ul class="navbar-nav navbar-right">
        <li>@Html.ActionLink("Sign in", "SignIn", "Account", routeValues: null, htmlAttributes: new { id = "loginLink", @class = "nav-link" })</li>
    </ul>
}

I added the signoutcallback.cshtml view to the Account folder in the View folder for sign-out purposes.

View/Account/SignOutCallback.cshtml:

@{
    ViewBag.Title = "Sign Out";
}

<main aria-labelledby="title">
    <h2 id="title">@ViewBag.Title.</h2>
    <p class="text-success">You have successfully signed out.</p>
</main>

I added the [Authorize] attribute to my controller, as shown below.

HomeController:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcWithAzureAd123.Controllers
{
    [Authorize]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";
            return View();
        }
        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";
            return View();
        }
    }
}

This is my Package.config, I downloaded the required NuGet packages, as shown below.

package.config:

<?xml version="1.0" encoding="utf-8"?>
<packages>
    <package id="Antlr" version="3.5.0.2" targetFramework="net48" />
    <package id="bootstrap" version="5.2.3" targetFramework="net48" />
    <package id="jQuery" version="3.4.1" targetFramework="net48" />
    <package id="jQuery.Validation" version="1.17.0" targetFramework="net48" />
    <package id="Microsoft.AspNet.Mvc" version="5.2.9" targetFramework="net48" />
    <package id="Microsoft.AspNet.Razor" version="3.2.9" targetFramework="net48" />
    <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net48" />
    <package id="Microsoft.AspNet.WebPages" version="3.2.9" targetFramework="net48" />
    <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.1" targetFramework="net48" />
    <package id="Microsoft.IdentityModel.JsonWebTokens" version="5.5.0" targetFramework="net48" />
    <package id="Microsoft.IdentityModel.Logging" version="5.5.0" targetFramework="net48" />
    <package id="Microsoft.IdentityModel.Protocol.Extensions" version="1.0.4.403061554" targetFramework="net48" />
    <package id="Microsoft.IdentityModel.Protocols" version="5.5.0" targetFramework="net48" />
    <package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="5.5.0" targetFramework="net48" />
    <package id="Microsoft.IdentityModel.Tokens" version="5.5.0" targetFramework="net48" />
    <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.11" targetFramework="net48" />
    <package id="Microsoft.Owin" version="4.2.2" targetFramework="net48" />
    <package id="Microsoft.Owin.Host.SystemWeb" version="4.2.2" targetFramework="net48" />
    <package id="Microsoft.Owin.Security" version="4.2.2" targetFramework="net48" />
    <package id="Microsoft.Owin.Security.Cookies" version="4.2.2" targetFramework="net48" />
    <package id="Microsoft.Owin.Security.OpenIdConnect" version="4.2.2" targetFramework="net48" />
    <package id="Microsoft.Web.Infrastructure" version="2.0.1" targetFramework="net48" />
    <package id="Modernizr" version="2.8.3" targetFramework="net48" />
    <package id="Newtonsoft.Json" version="12.0.2" targetFramework="net48" />
    <package id="Owin" version="1.0" targetFramework="net48" />
    <package id="System.IdentityModel.Tokens.Jwt" version="5.5.0" targetFramework="net48" />
    <package id="WebGrease" version="1.6.0" targetFramework="net48" />
</packages>

I added a Redirect URL to the App Registration, https://localhost:Port/signin-oidc as shown below:

enter image description here

After running the app, it asked me to pick an account, as shown below:

enter image description here

It asked me to accept the app registration.

enter image description here

OutPut:

enter image description here

Before publishing your app to Azure, change the PostLogoutRedirectUri value to https://<AzureWebAppName>.azurewebsites.net/.auth/login/aad/callback in web.config.

<appSettings>
  <add key="webpages:Version" value="3.0.0.0" />
  <add key="webpages:Enabled" value="false" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  <add key="ida:ClientId" value="<ClientId>" />
  <add key="ida:AADInstance" value="https://login.microsoftonline.com/" />
  <add key="ida:Domain" value="microsoft.onmicrosoft.com" />
  <add key="ida:TenantId" value="<TenanatId>" />
  <add key="ida:PostLogoutRedirectUri" value="https://kamvcwithazuread.azurewebsites.net/.auth/login/aad/callback" />
</appSettings>

I added an Identity provider in the Azure Web app as shown below:

enter image description here

I selected the Identity Provider as Microsoft and added my app registration.

enter image description here

It was added to the web app successfully, as shown below:

enter image description here

Then, I added the Redirect URI https://<WebAppName>.azurewebsites.net/.auth/login/aad/callback to my App Registration.

enter image description here

Azure App Service Output:

enter image description here