Friday, July 22, 2022

Authenticate .Net core web app using Azure AD

 In this tutorial you will see how to implement azure ad authentication/sso in .Net core app.

So lets start , I have tried to keep as simple as possible so basic things can be understood easily.

Steps.

Setting your App in Azure AD

1. Login to azure portal -> search for Azure Active Directory and click .


2. From Left Menu select App Registration and click on New Registrations


in the app name enter "AzureADSignOn" (you can enter your app name ) , keep default selected value in Supported Account types . 

Redirect Url - select web from dropdown and enter your redirect url where you want to redirect after successful login. in my case its "https://localhost:44319/index"

3. Click Authentication from Left Menu and check on ID Token and click on Save.




4. Go to overview menu and copy paste below in your local notepad as per below screen shot 
 1. Client Id 
2. TenantId
3. domain Name : you can find in your active directory overview



We are done with azure ad configuration. Let's see how to implement in .Net core web app.

Creating ASP.NET Core 5.0 web application

1.Open Visual Studio and create .Net core web app named "AzureADSignOn" click next and create.

2. Open appsetting.json and replace with below json

{
  "AzureAdConfig": {
    "Instance": "https://login.microsoftonline.com",
    "TenantId": "<<your tenantId>>",
    "ClientId": "<<your application Id/client Id>>",
    "Domain": "<<domain name>>",
    "CallbackPath": "/index"  <--this should be exact
same what u have enter in redirect url while registering app and starting with / always
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

3. Add below two NuGet Packages 

  • Microsoft.Identity.Web
  • Microsoft.AspNetCore.Authentication.AzureAD.UI

Choose based on your .Net Core version.

4. Open Startup.cs and add below  code which is highlighted in orange color.

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
 
namespace AzureADSignOn
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
 
        public IConfiguration Configuration { get; }
 
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
 //add this code
            services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAdConfig"));
 

            services.AddControllersWithViews();
        }
 
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
 
            app.UseRouting();
//add this code
            app.UseAuthentication();
            app.UseAuthorization();
 
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

 5. Go to HomeController and add below highlighted code in orange color


using AzureADSignOn.Models;
using
Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using
Microsoft.Extensions.Logging;
using System.Diagnostics;
 

namespace AzureADSignOn.Controllers

{

    [Authorize]
    
public class HomeController : Controller
    {

        
private readonly ILogger<HomeController> _logger;
        
public HomeController(ILogger<HomeController> logger)
        {
            
_logger = logger;
        } 
        public IActionResult Index()
        
{
            if (User.Identity.IsAuthenticated) // you can ignore this if dont need
            
{
               // you can capture claim and user details and do whatever need


            }
            return View(); 
        
}
 



        
public IActionResult Privacy()
        {



            
return View();
        }



 

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]



        
public IActionResult Error()
        {



            
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ??               HttpContext.TraceIdentifier });
        }


    }

}

6. open Index.cshtml view and replace with below code


@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome To azure ad authentication sample</h1>

</div>

@if (Context.User.Identity.IsAuthenticated)
{
    var user = Context.User;
    <h2>User Name : @user.Identity.Name</h2>

    @foreach (var claim in user.Claims)
    {
        <li>
            @claim.Type : @claim.Value
        </li>
    }
}

 

1. Once you run it redirect to Microsoft login page 


 Enter your user name and click next ,in next screen enter password . 

Note : first time it ask acceptance for access . accept that and continue.




After successful login it redirects to your app where you can see below output. I have shown few logged in user details.


And That's it. We have completed Azure Ad Authentication. 

Thanks . 

 


Get auth token from azure and use as authorization to call azure services

 In this tutorial I will show how can we generate authentication token from azure and use to call any rest api .

Scenario - Assume our requirement is to get token from azure and download one file from blob container by passing this token .

So Let’s follow below steps 

1. First login on azure portal and need to register an app.

GO to the azure portal and in search type "App Registrations" and click on the icon.



 

 

2. Next click on  "New Registration " and enter required data as below :



 

Name - tokenTestApp

Redirect url is optional here if you want you can enter as below after that click register


3. After successful registered app it will auto redirect to below screen - where you create client secret for this app





 

copy in your local  the value field from the client secret which is required in later stage . it shows only one time so don't forget to copy before leaving above page.

4. Now go to your resource and click on Access control from left menu .Click on Add button 


5. in the Role tab search with blob and you will find related predefined role ,select Storage Blob Data Contributor role and click next 



6. in member tab keep Assign access to default selection , click on select member and type your app name which you have created and click on select button . click review and assign. 





7. Now go back to your home -> App Registration -> Click tokenTestApp and click on API permission from left menu and click Add Permission



8. click on azure storage




9. Keep default selected delegated permission and check user impersonation and click Add Permission.



 Before we move in another section let copy required key value which need to use on later stage:

1.Client Id  & Tenant Id - Go to App Registrations and click on registered app from list ,copy     below in your local PC :



2. Secret Id - copy its value field which mentioned above

 Create Container and upload File which will be used to download later 

1. Go to storage account -> click Container from left menu then click add and enter lower case container name and click on create button


2. Click added container name in the list and upload file 



We have done with all azure side configuration now lets go to coding part where we are going to get token and pass in authorization header and download uploaded file .

1. Open visual studio and create .net core project and enter project name "AzureServiceTokenAuth" click next and create


2.
open appsettings.json and replace below keys value 

{
  "AppSettings": {
    "grant_type": "client_credentials",
    "client_Id": "clientId",
    "client_secret": "secret(value)",
    "resource": "https://storage.azure.com/.default",
    "msurl": "https://login.microsoftonline.com/tenantId/oauth2/v2.0/token"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}


3. Add AppSettings.cs file and enter below code


namespace AzureServiceTokenAuth
{
    public class AppSettings
    {
        public static AppSettings _settings;
        public AppSettings()
        {
            _settings = this;
        }
        public string grant_type { get; set; }
        public string client_Id { get; set; }
        public string client_secret { get; set; }
        public string resource { get; set; }
        public string msurl { get; set; }
       
    }
}



4. Replace startup.cs with below code

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;

namespace AzureServiceTokenAuth
{
    public class Startup
    {
        public Startup(IConfiguration configuration,IWebHostEnvironment env)
        {
            var builder = new ConfigurationBuilder()
           .SetBasePath(env.ContentRootPath)
           .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
            Configuration = builder.Build();
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<AppSettings>(Configuration);
            var appSettingsSection = Configuration.GetSection("AppSettings");
            appSettingsSection.Get<AppSettings>();

            services.AddSingleton<IAzureTokenService, AzureTokenService>();
            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "AzureServiceTokenAuth", Version = "v1" });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AzureServiceTokenAuth v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}


5. Add new class called "AzureTokenResult" with below code
namespace AzureServiceTokenAuth
{
    public class AzureTokenResult
    {      
   
        public string token_type { get; set; }

     
        public string expires_in { get; set; }

        public string ext_expires_in
        {
            get; set;
        }

       
        public string expires_on { get; set; }
     
        public string access_token { get; set; }

    }

    public class TokenStorage // to send back token while downloading file
    {
    public string Token { get; set; }
    }
}


6. Create new class "AzureTokenService" and replace with below code
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

namespace AzureServiceTokenAuth
{
    public class AzureTokenService : IAzureTokenService
    {
        private readonly HttpClient _httClient;
        public AzureTokenService()
        {
            _httClient = new HttpClient();
        }
        public async Task<AzureTokenResult> GetToken()
        {
            var dict = new Dictionary<string, string>
                {
                    { "grant_type", AppSettings._settings.grant_type },
                    { "client_id", AppSettings._settings.client_Id },
                    { "client_secret", AppSettings._settings.client_secret },
                    { "scope", AppSettings._settings.resource }
                };

            HttpContent formData = new FormUrlEncodedContent(dict);
            var response = await _httClient.PostAsync(AppSettings._settings.msurl, formData);
            response.EnsureSuccessStatusCode();
            var responseContent = await response.Content.ReadAsStringAsync();
            var result= JsonConvert.DeserializeObject< AzureTokenResult>(responseContent);
            return result;
        }

        public Stream GetStorage(string token)
        {

            _httClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
            _httClient.DefaultRequestHeaders.Add("x-ms-version", "2020-04-08");
            var response = _httClient.GetAsync("azurestorageurl/containername/fileName").Result;
           return response.Content.ReadAsStreamAsync().Result;
        }
    }
}


7. Create new interface "IAzureTokenService" and replace below code

 using System.IO;

using System.Threading.Tasks;

namespace AzureServiceTokenAuth
{
    public interface IAzureTokenService
    {
        Task<AzureTokenResult> GetToken();
        Stream GetStorage(string token);
    }
}

8. Add new controller in controller folder named "AuthTokenController" and replace below code 

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace AzureServiceTokenAuth.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class AuthTokenController : ControllerBase
    {

        private readonly ILogger<AuthTokenController> _logger;
        private readonly IAzureTokenService _azureTokenService;

        public AuthTokenController(ILogger<AuthTokenController> logger,
            IAzureTokenService azureTokenService)
        {
            _logger = logger;
            _azureTokenService = azureTokenService;
        }

        [HttpGet]
        public IActionResult Get()
        {
            return Ok("success");
        }
        [HttpGet]
        [Route("get-az-token")]
        public async Task<IActionResult> GetToken()
        {

            var result = await _azureTokenService.GetToken();
            return Ok(result);
        }
        [HttpPost]
        [Route("access-storage")]
        public IActionResult GetFiles([FromBody] TokenStorage token)
        {

           var stream= _azureTokenService.GetStorage(token.Token);
            return File(stream, "application/octet-stream", "downloadFile.pdf");
        }
       
    }
}



Now we are done with coding part lets run the project and see the output :

1. Getting token :

Execute above endpoint to get token , copy the below token







call access-storage endpoint and we get your uploaded file in blob storage 




Note : I use storage service just to show how we can use auth token to call azure services ,similarly you can use for other services also.

Thanks and we are done with Auth token and its use.

 you can download all the azure samples code : https://github.com/mkumar8184/azure-sdk-services-samples


Convert Html to Pdf in azure function and save in blob container

 In this post  I am going to create an azure function ( httpTrigger ) and send html content  which will be converted into PDF and save in bl...