如何在Azure App服务中托管的多个Web应用程序之间共享相同的.Net核心身份验证Cookie

时间:2019-11-20 06:01:45

标签: .net-core azure-web-sites asp.net-core-webapi cookie-authentication

花了几天的时间并尝试了社区推荐的各种解决方案后,我仍然找不到解决此问题的方法。
我有多个应用程序需要实现单点登录。所有的应用程序都有两个项目。前端应用程序和后端应用程序。前端应用程序是用ReactJS编写的,后端应用程序是.Net核心2.2编写的。所有应用程序都托管在Azure应用程序服务中。 例如,用户身份验证系统具有两个应用程序 authweb.mydomain.org (ReactJS)和 authbackend.mydomain.org (。Net核心)。所有其他应用程序都应通过该应用程序进行实例身份验证,app1具有两个Web应用程序 app1web.mydomain.org app1backend.mydomain.org < / em>
我选择了cookie身份验证方法来实现此单点登录(不确定这是此方案的最完美选择)。用户使用其用户名和密码登录auth应用程序( authweb.mydomain.org )。然后backend( 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
enter image description here

现在,用户希望使用相同的身份验证Cookie访问 app1web.mydomain.org 。当我打开 app1web.mydomain.org 时,这些cookie在浏览器cookie部分中是apprar。此应用程序在后端( 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 App Services时,它可以与localhost正常工作,但不能对app1进行身份验证。请有人向我解释我在这里错过的事情。非常感谢您的帮助。

0 个答案:

没有答案