Home > Back-end >  External Connection With MicrosoftIdentityWebApp And Identity
External Connection With MicrosoftIdentityWebApp And Identity

Time:12-17

I try to login User from Microsoft account into my app.

First : I'm following this info, and that'a working well. https://learn.microsoft.com/fr-fr/azure/active-directory/develop/web-app-quickstart?pivots=devlang-aspnet-core

But, when I try merge it with the classic Identity Login, on the external Login, this function return null all the time. And the login info on the starup is correct. I think it was a schema problem but I try to change it and it was not.

var info = await _signInManager.GetExternalLoginInfoAsync();


        public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
        {
            returnUrl = returnUrl ?? Url.Content("~/");
            if (remoteError != null)
            {
                ErrorMessage = $"Error from external provider: {remoteError}";
                return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
            }

            var userl = _signInManager.IsSignedIn(User);

            //ExternalLoginInfo info = new ExternalLoginInfo(User, "Microsoft", User.Claims.Where(x => x.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").FirstOrDefault().Value.ToString(), "Microsoft");
            var info = await _signInManager.GetExternalLoginInfoAsync();
            if (info == null)
            {
                ErrorMessage = "Error loading external login information.";
                return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
            }
            // Sign in the user with this external login provider if the user already has a login.
            var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
            if (result.Succeeded)
            {
                _logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider);
                return LocalRedirect(returnUrl);
            }
            if (result.IsLockedOut)
            {
                return RedirectToPage("./Lockout");
            }
            else
            {
                // If the user does not have an account, then ask the user to create an account.
                ReturnUrl = returnUrl;
                ProviderDisplayName = info.ProviderDisplayName;
                if (info.Principal.HasClaim(c => c.Type == ClaimTypes.Email))
                {
                    Input = new InputModel
                    {
                        Email = info.Principal.FindFirstValue(ClaimTypes.Email)
                    };
                }
                return Page();
            }
        }

Startup.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(connectionString));

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
    .AddRoles<IdentityRole>()
    .AddErrorDescriber<FrenchIdentityErrorDescriber>()
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services
    .AddControllersWithViews()
    .AddRazorRuntimeCompilation()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });

builder.Services.AddMvc();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromHours(8);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
    //options.Cookie.Name = "WebSignature.Session";
});

builder.Services.Configure<IdentityOptions>(options =>
{
    // Password settings.
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    options.Password.RequireNonAlphanumeric = true;
    options.Password.RequireUppercase = true;
    options.Password.RequiredLength = 6;
    options.Password.RequiredUniqueChars = 1;

    // Lockout settings.
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;

    // User settings.
    options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@ ";
    options.User.RequireUniqueEmail = false;
});

builder.Services.ConfigureApplicationCookie(options =>
{
    // Cookie settings
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromHours(12);
    options.LoginPath = ApplicationRedirection.PageConnexion;
    options.LogoutPath = "/Identity/Account/Logout";
    options.AccessDeniedPath = "/Erreurs/403";
    options.SlidingExpiration = true;
});

builder.Services
    .AddAuthentication()
    .AddJwtBearer(options =>
    {
        var SecretKey = builder.Configuration.GetSection("JwtToken").GetValue<string>("SecretKey") ?? string.Empty;
        var Audience = builder.Configuration.GetSection("JwtToken").GetValue<string>("Audience") ?? string.Empty;
        var Issuer = builder.Configuration.GetSection("JwtToken").GetValue<string>("Issuer") ?? string.Empty;

        options.RequireHttpsMetadata = false;
        options.SaveToken = true;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ClockSkew = TimeSpan.Zero,

            ValidateAudience = true,
            ValidAudience = Audience,
            ValidateIssuer = true,
            ValidIssuer = Issuer,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey))
        };
    });

builder.Services.AddAuthentication()
    .AddMicrosoftIdentityWebApp(options =>
    {
        var config = builder.Configuration.GetSection("AzureAd");
        options.Instance = config["Instance"];
        options.Domain = config["Domain"];
        options.ClientId = config["ClientId"];
        options.TenantId = config["TenantId"];
        options.ClientSecret = config["ClientSecret"];
        options.CallbackPath = config["CallbackPath"];

        options.RequireHttpsMetadata = true;
        options.GetClaimsFromUserInfoEndpoint = true;
        options.SaveTokens = true;
        options.UsePkce = true;
        options.ResponseType = OpenIdConnectResponseType.Code;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true
        };
    })
    .EnableTokenAcquisitionToCallDownstreamApi(builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' '))
    .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
    .AddInMemoryTokenCaches();

builder.Services.AddControllersWithViews(options =>
{
    var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy(PolicyApplication.Administrateur, policy => policy.RequireAuthenticatedUser().RequireRole(RoleUtilisateur.Administrateur)/*.AddAuthenticationSchemes(IdentityConstants.ApplicationScheme)*/);
    options.AddPolicy(PolicyApplication.Utilisateur, policy => policy.RequireAuthenticatedUser().RequireRole(RoleUtilisateur.Utilisateur)/*.AddAuthenticationSchemes(IdentityConstants.ApplicationScheme)*/);

    /// Récupère tous les roles de la class
    var AllRole = typeof(RoleUtilisateur).GetFields().Select(x => x.GetValue(x.Name)?.ToString() ?? "").ToArray();
    options.AddPolicy(PolicyApplication.All, policy => policy.RequireAuthenticatedUser().RequireRole(AllRole)/*.AddAuthenticationSchemes(IdentityConstants.ApplicationScheme)*/);

    /// Pour l'API
    options.AddPolicy(PolicyApplication.API, policy => policy.RequireAuthenticatedUser().AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme));
});

builder.Services.Configure<GzipCompressionProviderOptions>(o => o.Level = CompressionLevel.Optimal);
builder.Services.AddKendo();
builder.Services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");



builder.Services.AddRazorPages()
    .AddMicrosoftIdentityUI();

var app = builder.Build();
var supportedCultures = new[] { new CultureInfo("fr-FR") };
app.UseRequestLocalization(new RequestLocalizationOptions()
{
    DefaultRequestCulture = new RequestCulture(new CultureInfo("fr-FR")),
    SupportedCultures = supportedCultures,
    SupportedUICultures = supportedCultures
});

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/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.UseSwagger();
app.UseSwaggerUI();

app.UseStatusCodePages(context =>
{
...

    return Task.CompletedTask;
});


app.UseSession();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    endpoints.MapRazorPages();
});

app.Run();

Value Null

I the problem is due to the claims who was empty. But i don't know why. enter image description here

So what is wrong, any ideas ?

CodePudding user response:

Finally I found.

Simply use that

builder.Services.AddAuthentication()
.AddMicrosoftAccount(options =>
{
    var config = builder.Configuration.GetSection("AzureAd");
    options.ClientId = config["ClientId"] ?? string.Empty;
    options.ClientSecret = config["ClientSecret"] ?? string.Empty;
    options.CallbackPath = config["CallbackPath"] ?? string.Empty;
});

than

builder.Services.AddAuthentication()
.AddMicrosoftIdentityWebApp(options =>
{
    var config = builder.Configuration.GetSection("AzureAd");
    options.Instance = config["Instance"];
    options.Domain = config["Domain"];
    options.ClientId = config["ClientId"];
    options.TenantId = config["TenantId"];
    options.ClientSecret = config["ClientSecret"];
    options.CallbackPath = config["CallbackPath"];

    options.RequireHttpsMetadata = true;
    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;
    options.UsePkce = true;
    options.ResponseType = OpenIdConnectResponseType.Code;
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true
    };
})
.EnableTokenAcquisitionToCallDownstreamApi(builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' '))
.AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
  • Related