【问题标题】:Microsoft Authentication in ASP.NET Core 2 and Azure App ServicesASP.NET Core 2 和 Azure 应用服务中的 Microsoft 身份验证
【发布时间】:2018-05-19 18:19:25
【问题描述】:

我在 GitHub 有以下应用程序,并将其部署到 Azure 应用服务上的 https://stratml.services,身份验证定义为 Microsoft 帐户,任何请求都需要 Microsoft 帐户登录。然而,在“prod”中会发生此挑战https://stratml.services/Home/IdentityName 不返回任何内容。

我一直在关注thisthis,但是我不想使用 EntityFramework,从后者的描述来看,这似乎暗示如果我正确配置了我的身份验证方案,我不必这样做。

以下代码在我的 Start 类中:

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = MicrosoftAccountDefaults.AuthenticationScheme;
        }).AddMicrosoftAccount(microsoftOptions =>
        {
            microsoftOptions.ClientId = Configuration["Authentication:AppId"];
            microsoftOptions.ClientSecret = Configuration["Authentication:Key"];
            microsoftOptions.CallbackPath = new PathString("/.auth/login/microsoftaccount/callback");

        });

更新:感谢我能够得到的第一个答案,它现在授权给 Microsoft 并尝试向我的应用程序反馈,但是我收到以下错误:

InvalidOperationException: No IAuthenticationSignInHandler is configured to handle sign in for the scheme: Cookies

请访问https://stratml.services/Home/IdentityName,GitHub 已更新。

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = MicrosoftAccountDefaults.AuthenticationScheme;
        }).AddCookie(option =>
        {
            option.Cookie.Name = ".myAuth"; //optional setting
        }).AddMicrosoftAccount(microsoftOptions =>
        {
            microsoftOptions.ClientId = Configuration["Authentication:AppId"];
            microsoftOptions.ClientSecret = Configuration["Authentication:Key"];

        });

【问题讨论】:

    标签: c# azure authentication asp.net-core-2.0


    【解决方案1】:

    我已经检查过这个问题,根据我的测试,您可以按如下方式配置您的设置:

    ConfigureServices方法下,添加cookie和MSA认证服务。

    services.AddAuthentication(options =>
    {
        options.DefaultChallengeScheme = MicrosoftAccountDefaults.AuthenticationScheme;
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(option =>
    {
        option.Cookie.Name = ".myAuth"; //optional setting
    })
    .AddMicrosoftAccount(microsoftOptions =>
    {
        microsoftOptions.ClientId = Configuration["Authentication:AppId"];
        microsoftOptions.ClientSecret = Configuration["Authentication:Key"];
    });
    

    Configure方法下,添加app.UseAuthentication()

    测试:

    [Authorize]
    public IActionResult Index()
    {
        return Content(this.User.Identity.Name);
    }
    

    当我查看您的在线网站时,我发现您使用的是Authentication and authorization in Azure App ServiceAuthenticate with Microsoft account

    AFAIK,当使用应用服务身份验证时,无法将声明附加到当前用户,您可以通过Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"] 检索身份名称,或者您可以按照类似的issue 手动附加当前用户的所有声明。

    通常,您可以在应用程序中手动启用身份验证中间件,也可以仅利用 Azure 提供的应用服务身份验证,而无需更改启用身份验证的代码。此外,您可以Remote debugging web apps 对您的应用程序进行故障排除。

    更新:

    为了在我的代码中启用 MSA 身份验证并在部署到 Azure 时对其进行测试,我禁用了应用服务身份验证,然后将我的应用程序部署到 Azure Web 应用程序。我打开了一个新的隐身窗口,发现我的网络应用可以正常运行。

    如果您想在本地模拟 MSA 登录并在部署到 azure 时使用 Easy Auth,我假设您可以在 appsettings.json 中设置一个设置值并手动为 dev 添加身份验证中间件并覆盖 azure 上的设置,详情可以关注here。您可以使用相同的应用程序 ID 并配置以下重定向 url:

    https://stratml.services/.auth/login/microsoftaccount/callback //for easy auth
    https://localhost:44337/signin-microsoft //manually MSA authentication for dev locally
    

    此外,您可以按照issue 手动附加当前用户的所有声明。然后,您可以以与手动 MSA 身份验证和 Easy Auth 相同的方式检索用户声明。

    【讨论】:

    • 我真的不明白回调 URL 是如何工作的,Azure 提供了一个有效的 URL,但是我收到一个错误,我提供的那个是无效的。我是否需要在那里创建某种着陆点或其他东西或进行额外的布线?然而,这非常接近我想要的。尽管我很喜欢 Azure 这个项目,但我不希望代码依赖它。
    • 我刚刚更新了一些测试的答案,你可以参考一下。
    【解决方案2】:

    如果您使用的是应用服务身份验证 (EasyAuth),根据 Microsoft 文档page

    应用服务通过使用特殊标头将一些用户信息传递给您的应用程序。外部请求禁止这些标头,并且仅在应用服务身份验证/授权设置时才会出现。一些示例标题包括:

    X-MS-CLIENT-PRINCIPAL-NAME

    X-MS-CLIENT-PRINCIPAL-ID

    X-MS-TOKEN-FACEBOOK-ACCESS-TOKEN

    X-MS-TOKEN-FACEBOOK-EXPIRES-ON

    以任何语言或框架编写的代码都可以从这些标头中获取所需的信息。对于 ASP.NET 4.6 应用,ClaimsPrincipal 会自动设置为适当的值。

    所以基本上,如果您使用的是 ASP.NET Core 2.0,则需要手动设置 ClaimPrincipal。您需要使用什么来获取此标头并设置 ClaimsPrincipal 是AuthenticationHandler

    public class AppServiceAuthenticationOptions : AuthenticationSchemeOptions
    {
        public AppServiceAuthenticationOptions()
        {
        }
    }
    
    internal class AppServiceAuthenticationHandler : AuthenticationHandler<AppServiceAuthenticationOptions>
    {
        public AppServiceAuthenticationHandler(
            IOptionsMonitor<AppServiceAuthenticationOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock) : base(options, logger, encoder, clock)
        {
        }
    
        protected override Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            return Task.FromResult(FetchAuthDetailsFromHeaders());
        }
    
        private AuthenticateResult FetchAuthDetailsFromHeaders()
        {
            Logger.LogInformation("starting authentication handler for app service authentication");
    
            if (Context.User == null || Context.User.Identity == null || Context.User.Identity.IsAuthenticated == false)
            {
                Logger.LogDebug("identity not found, attempting to fetch from the request headers");
    
                if (Context.Request.Headers.ContainsKey("X-MS-CLIENT-PRINCIPAL-ID"))
                {
                    var headerId = Context.Request.Headers["X-MS-CLIENT-PRINCIPAL-ID"][0];
                    var headerName = Context.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"][0];
    
                    var claims = new Claim[] {
                        new Claim("http://schemas.microsoft.com/identity/claims/objectidentifier", headerId),
                        new Claim("name", headerName)
                    };
                    Logger.LogDebug($"Populating claims with id: {headerId} | name: {headerName}");
    
                    var identity = new GenericIdentity(headerName);
                    identity.AddClaims(claims);
    
                    var principal = new GenericPrincipal(identity, null);
                    var ticket = new AuthenticationTicket(principal,
                        new AuthenticationProperties(),
                        Scheme.Name);
    
                    Context.User = principal;
                    return AuthenticateResult.Success(ticket);
                }
                else
                {
                    return AuthenticateResult.Fail("Could not found the X-MS-CLIENT-PRINCIPAL-ID key in the headers");
                }
            }
    
            Logger.LogInformation("identity already set, skipping middleware");
            return AuthenticateResult.NoResult();
        }
    }
    

    然后您可以为中间件编写扩展方法

    public static class AppServiceAuthExtensions
    {
        public static AuthenticationBuilder AddAppServiceAuthentication(this AuthenticationBuilder builder, Action<AppServiceAuthenticationOptions> configureOptions)
        {
            return builder.AddScheme<AppServiceAuthenticationOptions, AppServiceAuthenticationHandler>("AppServiceAuth", "Azure App Service EasyAuth", configureOptions);
        }
    }
    

    并在Configure() 方法中添加app.UseAuthentication();,并在您的启动类的ConfigureServices() 方法中添加以下内容。

    services
        .AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = "AppServiceAuth";
            options.DefaultChallengeScheme = "AppServiceAuth";
        })
        .AddAppServiceAuthentication(o => { });
    

    如果您需要完整的索赔详情,您可以通过向 /.auth/me 发出请求,在 AuthenticationHandler 上检索它,并使用您在请求中收到的相同 cookie。

    【讨论】:

    • 所以这将取代 MicrosoftAccount?有 ant 方法可以在本地模拟吗?
    • 是的,您需要用此替换您的 Microsoft 帐户身份验证方案,因为您使用的是 App Service EasyAuth。 AFAIK,目前没有办法在本地模拟这个。另一方面,您可以将AuthenticationHandler 配置为跳过检查并立即返回AuthenticationResult.NoResult(),例如:环境就是发展。
    猜你喜欢
    • 2018-05-13
    • 1970-01-01
    • 2018-08-15
    • 2020-07-27
    • 2019-01-24
    • 1970-01-01
    • 2020-07-26
    • 1970-01-01
    • 2019-12-13
    相关资源
    最近更新 更多