gpt4 book ai didi

c# - ASP.NET核心6 : permit Azure AD authentication and local authentication

转载 作者:行者123 更新时间:2023-12-02 23:54:41 27 4
gpt4 key购买 nike

我正在开发一个程序,该程序允许用户以两种方式进行身份验证。他们可以通过任何电子邮件创建和使用本地(自制)帐户;或者他们可以仅对我们的组织使用 Azure AD OAuth。无论使用哪种身份验证方法,都应同等对待用户,并在 context.User.Identity.IsAuthenticated 上返回 true。

我遇到了仅 Azure AD 方法有效的问题,为了解决此问题,我使用了身份验证策略 inspired by this article 。然而,在遵循它之后,两种身份验证方法似乎都不起作用:(

以下是 startup.cs 中的服务代码:

services.AddJwtAuthorization();

services.AddAuthentication(o =>
{
o.DefaultScheme = "MultiAuthSchemes";
o.DefaultChallengeScheme = "MultiAuthSchemes";
})
.AddCookie(o =>
{
o.LoginPath = "/login";
})
.AddJwtBearer("HomebrewScheme", _ => { })
.AddPolicyScheme("MultiAuthSchemes", JwtBearerDefaults.AuthenticationScheme, options =>
{
options.ForwardDefaultSelector = context =>
{
string authorization = context.Request.Headers[HeaderNames.Authorization];
if (!string.IsNullOrEmpty(authorization) && authorization.Contains("Bearer "))
{
var token = authorization["Bearer ".Length..].Trim();
var jwtHandler = new JwtSecurityTokenHandler();
return jwtHandler.CanReadToken(token)
? "HomebrewScheme" : "AdScheme";
}
return CookieAuthenticationDefaults.AuthenticationScheme;
};
})
.AddMicrosoftIdentityWebApi(Config, "AzureAd", "AdScheme");

services.AddAuthorization(o =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme,
CookieAuthenticationDefaults.AuthenticationScheme,
"HomebrewScheme", "AdScheme");
defaultAuthorizationPolicyBuilder =
defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
o.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();

var onlySecondJwtSchemePolicyBuilder = new AuthorizationPolicyBuilder("HomebrewScheme");
o.AddPolicy("OnlyHomebrewScheme", onlySecondJwtSchemePolicyBuilder
.RequireAuthenticatedUser()
.AddAuthenticationSchemes()
.Build());
var onlyCookieSchemePolicyBuilder = new AuthorizationPolicyBuilder("AdScheme");
o.AddPolicy("OnlyAdScheme", onlyCookieSchemePolicyBuilder
.RequireAuthenticatedUser()
.Build());
});

以下是 startup.cs 中的应用代码:

app.UseAuthentication()

app.UseGraphQLPlayground(new PlaygroundOptions
{
GraphQLEndPoint = GraphQLApiEndpoint
});
app.UseWebSockets();
app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(x => x.MapGraphQL(path: GraphQLApiEndpoint));

这是 startup.cs 中的代码,我用它来测试身份验证:

app.Use((context, next) =>
{
//Grab the first identity because the authentication type does not matter
if (context.User.Identity?.IsAuthenticated == true)
{
PermissionLevel = Permissions.Authorized;
}
});

从调试中可以看出,系统从未检测到我现在获得了身份验证。我知道前端可以正常工作,因为如果我仅使用 services.AddMicrosoftIdentityWebApiAuthentication(Config, "AzureAd", "AdScheme"); 无论它是否是默认方案,一切都会正常。

感谢您的帮助,一直在解决这个问题😊

最佳答案

首先,我关注了this blog在我的代码中添加 Cookie 身份验证。它提供了一个登录页面让我们登录。并且在AccountController中,它提供了几个模拟用户帐户,以便我们可以使用它们来登录进行测试。

然后,我在登录页面中添加了代码,以便提供使用 AAD 登录的选项。

更改 Program.cs 文件以添加多个身份验证方案。

这是我的代码,Program.cs

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;

var builder = WebApplication.CreateBuilder(args);

//set CookieAuthenticationDefaults.AuthenticationScheme as the default authentication scheme
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(x => x.LoginPath = "/account/login");
builder.Services.AddAuthentication()
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"), OpenIdConnectDefaults.AuthenticationScheme, "ADCookies");

// Add microsoft sign in page
builder.Services.AddControllersWithViews().AddMicrosoftIdentityUI();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
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();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

我的家庭 Controller

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using WebAppMvcCookieAuthAad.Models;

namespace WebAppMvcCookieAuthAad.Controllers
{
[AllowAnonymous]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}

[Authorize]
public async Task<IActionResult> ConfidentialDataAsync()
{
return View();
}
}
}

我的帐户 Controller :

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using WebAppMvcCookieAuthAad.Models;

namespace WebAppMvcCookieAuthAad.Controllers
{
public class AccountController : Controller
{
public List<UserModel> users = null;
public AccountController()
{
users = new List<UserModel>();
users.Add(new UserModel()
{
UserId = 1,
Username = "Tiny",
Password = "123",
Role = "Admin"
});
users.Add(new UserModel()
{
UserId = 2,
Username = "Other",
Password = "123",
Role = "User"
});
}
public IActionResult Login(string ReturnUrl = "/")
{
LoginModel objLoginModel = new LoginModel();
objLoginModel.ReturnUrl = ReturnUrl;
return View(objLoginModel);
}
[HttpPost]
public async Task<IActionResult> Login(LoginModel objLoginModel)
{
if (ModelState.IsValid)
{
var user = users.Where(x => x.Username == objLoginModel.UserName && x.Password == objLoginModel.Password).FirstOrDefault();
if (user == null)
{
ViewBag.Message = "Invalid Credential";
return View(objLoginModel);
}
else
{
var claims = new List<Claim>() {
new Claim(ClaimTypes.NameIdentifier, Convert.ToString(user.UserId)),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, user.Role),
new Claim("FavoriteDrink", "Tea")
};
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties()
{
IsPersistent = objLoginModel.RememberLogin
});
return LocalRedirect(objLoginModel.ReturnUrl);
}
}
return View(objLoginModel);
}
public async Task<IActionResult> LogOut()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return LocalRedirect("/");
}
}
}

我的登录模型和用户模型

using System.ComponentModel.DataAnnotations;

namespace WebAppMvcCookieAuthAad.Models
{
public class LoginModel
{
[Required]
[Display(Name = "Username")]
public string UserName{get;set;}
[Required]
[DataType(DataType.Password)]
public string Password{get;set;}
public bool RememberLogin{get;set;}
public string ReturnUrl{get;set;}
}
}

namespace WebAppMvcCookieAuthAad.Models
{
public class UserModel
{
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Role { get; set; }
}
}

查看 -> 帐户 -> Login.cshtml:

@model WebAppMvcCookieAuthAad.Models.LoginModel
@{
ViewData["Title"] = "Login";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Login</h2>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Login">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<span class="text-danger">
@ViewBag.Message
</span>
}
@Html.HiddenFor(x => x.ReturnUrl)
<div class="form-group">
<label asp-for="UserName" class="control-label"></label>
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password" class="control-label"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input asp-for="RememberLogin" /> @Html.DisplayNameFor(model => model.RememberLogin)
</label>
</div>
</div>
<div class="form-group">
<input type="submit" value="Login" />
</div>
</form>
</div>
</div>

<div>
<label>sign in with aad</label>
<a asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in with aad</a>
</div>

查看 -> 主页 -> ConfidentialData.cshtml

@if(User.Identity.IsAuthenticated){
<table>
@foreach (var item in User.Claims)
{
<tr><td>@item.Type</td><td>@item.Value</td></tr>
}
</table>
}

View -> Shared -> _LoginPartial.cshtml,请不要忘记将此部分 View 添加到布局中。

@using System.Security.Principal

<ul class="navbar-nav">
@if (User.Identity.IsAuthenticated)
{
<li class="nav-item">
<span class="navbar-text text-dark">Hello @User.Identity.Name!</span>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-controller="Account" asp-action="LogOut">log out</a>
</li>
@*asp - area = "MicrosoftIdentity"*@
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-controller="Account" asp-action="Login">log in</a>
</li>
}
</ul>

appsetting.json:

{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "tenant_name",
"TenantId": "tenant_id",
"ClientId": "azure_ad_app_id",
"ClientSecret": "azure_ad_client_secret",
"CallbackPath": "/home", //don't forget to set redirect url in azure portal
"SignedOutCallbackPath ": "/signout-callback-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

这段代码在我这边运行良好,我可以使用 cookie auth 和 aad 登录。我注意到使用 aad 签名后,@User.Identity.Name 将不会显示用户名。但实际上登录流程成功了。

enter image description here

关于c# - ASP.NET核心6 : permit Azure AD authentication and local authentication,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73760373/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com