在花了几天时间尝试了社区推荐的各种解决方案之后,我仍然找不到解决这个问题的方法。
我有多个应用程序需要实现单点登录。所有的应用程序都有两个项目。前端应用程序和后端应用程序。前端应用程序是用 ReactJS 编写的,后端是用 .Net core 2.2 编写的。所有应用程序都托管在 Azure 应用服务中。例如,用户身份验证系统有两个应用程序authweb.mydomain.org (ReactJS) 和authbackend.mydomain.org (.Net Core)。对于一个实例,所有其他应用程序都应通过此应用程序进行身份验证,app1 有两个 Web 应用程序app1web.mydomain.org和app1backend.mydomain.org
我选择了 cookie 身份验证方法来实现这个单点登录(不确定这是这个 scnario 的最完美选择)。用户使用他/她的用户名和密码登录到身份验证应用程序 ( authweb.mydomain.org )。然后后端(authbackend.mydomain.org)验证用户并在凭据有效时生成身份验证 cookie。这里我就不提我的ReactJs前端的源码了
authbackend.mydomain.org 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.AddDataProtection()
.SetApplicationName("SharedCookieApp");
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
})
.AddCookie("Cookies", options =>
{
options.Cookie.Name = "auth_cookie";
options.Cookie.SameSite = SameSiteMode.None;
options.LoginPath = "/Account/Login/";
options.LogoutPath = "/Account/Logout/";
options.Cookie.Domain = ".mydoamin.org";
options.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = redirectContext =>
{
redirectContext.HttpContext.Response.StatusCode = 401;
return Task.CompletedTask;
}
};
//options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"c:\shared-auth-ticket-keys\"));
});
services.AddHttpContextAccessor();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder => builder.AllowAnyHeader().AllowAnyMethod().SetIsOriginAllowed(_ => true).AllowCredentials());
});
}
// 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();
}
app.UseCors("AllowSpecificOrigin");
app.UseAuthentication();
app.UseMvc();
}
}
authbackend.mydomain.org AccountController.cs 对用户进行身份验证
[EnableCors("AllowSpecificOrigin")]
[Route("[controller]/[action]")]
[ApiController]
public class AccountController : ControllerBase
{
[HttpPost]
[AllowAnonymous]
public async Task<UserObject> Login([FromBody] UserLogin user)
{
try
{
if(user.UserName=="demo" && user.Password == "demo")
{
UserObject loggedInUser = UserObject.GetUser();
var identity = new ClaimsIdentity("Cookies");
identity.AddClaim(new Claim(ClaimTypes.Name, loggedInUser.UserName));
identity.AddClaim(new Claim(ClaimTypes.GivenName, loggedInUser.FirstName));
identity.AddClaim(new Claim(ClaimTypes.Surname, loggedInUser.LastName));
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync("Cookies",principal);
return loggedInUser;
}
return null;
}
catch (Exception ex)
{
throw ex;
}
}
[HttpPost]
public async Task<bool> Logout()
{
await HttpContext.SignOutAsync();
return true;
}
}
一旦用户登录到 auth 应用程序,就会生成 auth cookie,并将用户重定向到 auth 应用程序的主页
authbackend.mydomain.org HomeController.cs
[Authorize(AuthenticationSchemes= "Cookies")]
[EnableCors("AllowSpecificOrigin")]
[Route("[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
public string Index()
{
var usr = User;
var cookie = Request.Cookies;
var headerCookie = Request.HttpContext.Request.Cookies;
return "User is authenticated";
}
}
现在用户想要使用相同的身份验证 Cookie访问app1web.mydomain.org 。当我打开app1web.mydomain.org时,这些 cookie 在浏览器 cookie 部分中显示。此应用程序在其后端 ( app1backend.mydomain.org ) 中验证用户,以确保用户已通过身份验证。
app1backend.mydomain.org 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.AddDataProtection()
//.PersistKeysToFileSystem(new DirectoryInfo(@"c:\shared-auth-ticket-keys\"))
.SetApplicationName("SharedCookieApp");
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
})
.AddCookie("Cookies", options =>
{
options.Cookie.Name = "auth_cookie";
options.Cookie.SameSite = SameSiteMode.None;
options.LoginPath = "/Account/Login/";
options.LogoutPath = "/Account/Logout/";
options.Cookie.Domain = ".mydomain.org";
options.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = redirectContext =>
{
redirectContext.HttpContext.Response.StatusCode = 401;
return Task.CompletedTask;
}
};
});
services.AddHttpContextAccessor();
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder => builder.AllowAnyHeader().AllowAnyMethod().SetIsOriginAllowed(_ => true).AllowCredentials());
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// 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();
}
app.UseCors("AllowSpecificOrigin");
app.UseAuthentication();
app.UseMvc();
}
}
app1backend.mydomain.org HomeController.js
[Authorize(AuthenticationSchemes = "Cookies")]
[EnableCors("AllowSpecificOrigin")]
[Route("[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
[HttpGet]
public string Index()
{
var usr = User;
var cookie = Request.Cookies;
var headerCookie = Request.HttpContext.Request.Cookies;
return Request.HttpContext.Request.Cookies["auth_cookie"];
}
}
当我调用上面的 Index 方法时,401-Unauthorized 从后端返回。但是 cookie 正在传递到后端。
当我将应用程序托管到 Azure 应用服务时,这在 localhost 上运行良好,但没有对 app1 进行身份验证。请有人解释一下我在这里错过了什么。非常感谢您的帮助。