如何解决带有 React SPA 和 dot net core 后端的 ADFS 无法检索声明
我一直在努力在 ReactJs SPA 前端和 dot net core 3.1 作为后端应用程序中实现 ADFS, 以前,我已经在带有剃刀页面前端的 dot net core MVC web 应用程序中成功实现了 ADFS,没有任何问题,我已经能够验证和检索外部登录声明,
所以这就是我想出的 我的 startup.cs 类
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)
{
services.AddAuthentication().AddCookie("CustomCookie")
.AddWsFederation(options =>
{
options.SignInScheme = "CustomCookie";
// MetadataAddress represents the Active Directory instance used to authenticate users.
options.MetadataAddress = "https://login.microsoftonline.com/{TenantID}/federationmetadata/2007-06/federationmetadata.xml?appid=XXXXXXXXXXXXXXXXXXXXXXX";
// Wtrealm is the app's identifier in the Active Directory instance.
// For ADFS,use the relying party's identifier,its WS-Federation Passive protocol URL:
options.Wtrealm = "http://localhost:61974/";
options.Wreply = "http://localhost:61974/signin-wsfed";
//options.Wreply = "http://localhost:44312/Account/InternalLoginCallback";
// options.CallbackPath = new PathString("/signin-wsfed");
// options.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/signin-wsfed");
// options.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/Account/InternalLoginCallback/");
// For AAD,use the Application ID URI from the app registration's Overview blade:
// options. = "api://bbd35166-7c13-49f3-8041-9551f2847b69";
options.Events = new WsFederationEvents
{
//OnAuthenticationFailed = (context) =>
//{
// failed(context);
// return Task.FromResult<object>(null);
//},//OnSecurityTokenReceived = (context) =>
//{
// received(context);
// return Task.FromResult<object>(null);
//},OnSecurityTokenValidated = (context) =>
{
configureClaims(context);
return Task.FromResult<object>(null);
}
};
}).AddCookie();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.Strict;
});
// In production,the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
private void configureClaims(SecurityTokenValidatedContext context)
{
var identity = context.Principal.Identity as ClaimsIdentity;
Claim nameIdentifier = identity.Claims.Where(c => c.Type.EndsWith("nameidentifier")).FirstOrDefault();
Claim emailidentifier = identity.Claims.Where(c => c.Type.EndsWith("emailaddress")).FirstOrDefault();
string usernameValue = nameIdentifier.Value;
if (usernameValue.Contains("@"))
usernameValue = usernameValue.Split('@').First();
string emailValue = emailidentifier.Value;
Claim name = identity.Claims.Where(c => c.Type.EndsWith("claims/name")).FirstOrDefault();
identity.RemoveClaim(name);
identity.AddClaim(new Claim(ClaimTypes.Name,usernameValue));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseAuthentication();
app.UseCors(policy => policy.SetIsOriginAllowed(origin => origin == "https://login.microsoftonline.com"));
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseCookiePolicy();
app.UseMvcWithDefaultRoute();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",template: "{controller}/{action=Index}/{id?}");
routes.MapRoute("signin-wsfed","signin-wsfed",defaults: new { Controller = "Account",Action = "InternalLoginCallback" });
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
我的帐户控制器类
public class AccountController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> InternalLogin(string returnUrl = null)
{
string provider = "WsFederation";
//Clear the existing external cookie to ensure a clean login process
//await HttpContext.SignOutAsync(WsFederationDefaults.AuthenticationScheme);
ViewData["ReturnUrl"] = returnUrl;
var redirectUrl = Url.Action(nameof(InternalLoginCallback),"Account");
var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
return Challenge(properties,provider);
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> InternalLoginCallback()
{
var x = 10;
var info = await HttpContext.AuthenticateAsync("CustomCookie");
if (info == null)
{
return RedirectToAction(nameof(InternalLogin));
}
return Redirect("/");
// var signInResult = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider,info.ProviderKey,isPersistent: false,bypassTwoFactor: true);
}
}
带有登录按钮的 Home.js 类,用于在点击时进行挑战
import React,{ Component } from 'react';
export class Home extends Component {
constructor(props: any) {
super(props);
this.AADLogin = this.AADLogin.bind(this);
}
AADLogin() {
window.location.href = 'http://localhost:61974/Account/InternalLogin';
}
render() {
return (
<div>
<h1>Hello,world!</h1>
<p><button onClick={this.AADLogin} >AAD Login</button></p>
</div>
);
}
}
我在使用 SAML SSO 的 azure 门户中创建了一个应用程序,因此我获取了元数据 url、标识符和回复 url 并将其放入我的 startup.cs,然后我尝试运行该应用程序,我能够得到单击登录时的 microsoft 登录屏幕,我输入我的凭据,然后我希望在 InternalLoginCallback 函数中得到声明,但我没有得到任何声明
var info = await HttpContext.AuthenticateAsync("CustomCookie");
我得到的只是信息为空或返回关联失败。在远程登录期间的 Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler 异常,任何人都可以帮助我吗?谢谢。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。