如何为API和UI设置不同的身份验证

保罗·登普西

我正在使用ASP.NetCore 2.2(可能很快会升级到3.0)。我有一个Azure App Service应用程序。

我希望有一个API,客户端将使用API​​令牌(客户端密钥)进行身份验证,以便它们可以运行而无需交互式授权。

UI部分将需要Azure Active Directory身份验证。

如何将这两种不同的auth方法连接到ASP.Net Core应用程序?

负数

如何

  1. 首先,我们需要一个AuthenticationHandlerOptions来使用API​​令牌(客户端密钥)对请求进行身份验证。假设您已经创建了这样的身份验证处理程序和选项:

    public class ClientSecretAuthenOpts : AuthenticationSchemeOptions
    {
        public const string DefaultAuthenticationSchemeName = "ClientSecret";
    }
    
    public class ClientSecretAuthenticationHandler : AuthenticationHandler<ClientSecretAuthenOpts>
    {
        public ClientSecretAuthenticationHandler(IOptionsMonitor<ClientSecretAuthenOpts> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) 
            : base(options, logger, encoder, clock) { }
    
        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            // ... authenticate request 
        }
    }
    
  2. 然后一个接一个地注册多个身份验证方案

    // add mulitple authentication schemes
    services.AddAuthentication(AzureADDefaults.AuthenticationScheme)           // set AzureAD as the default for users (using the UI)
        .AddAzureAD(options => Configuration.Bind("AzureAD", options))         // setup AzureAD Authentication
        .AddScheme<ClientSecretAuthenOpts,ClientSecretAuthenticationHandler>(  // setup ClientSecret Authentication
            ClientSecretAuthenOpts.DefaultAuthenticationSchemeName,
            opts=>{ }
        );
    
    // post configuration for OIDC
    services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>{
        options.Authority = options.Authority + "/v2.0/";         // Microsoft identity platform
        options.TokenValidationParameters.ValidateIssuer = false; // accept several tenants 
    });
    
  3. 最后,为了同时启用多个身份验证方案,我们需要覆盖默认策略

    services.AddAuthorization(opts => {
        // allow AzureAD & our own ClientSecret Authentication at the same time
        var pb = new AuthorizationPolicyBuilder(
            ClientSecretAuthenOpts.DefaultAuthenticationSchemeName,
            "AzureAD"
        );  
        opts.DefaultPolicy = pb.RequireAuthenticatedUser().Build();
    });
    

演示与测试

假设您的API令牌(客户端机密)是通过“请求标头”发送的,如下所示:

GET https:// localhost:5001 / Home / Privacy HTTP / 1.1
 Api-Subscription-Id:Smith
 Api-Subscription-Key:最高机密

为了避免对标题名称进行硬编码,我在选项中添加了两个属性:

public class ClientSecretAuthenOpts : AuthenticationSchemeOptions
{
    public const string DefaultAuthenticationSchemeName = "ClientSecret";
    public string ApiClientIdHeadername {get;set;}= "Api-Subscription-Id";
    public string ApiClientTokenHeaderName {get;set;}= "Api-Subscription-Key";
}

为了对上述请求进行身份验证,我创建了一个自定义身份验证处理程序,如下所示:

public class ClientSecretAuthenticationHandler : AuthenticationHandler<ClientSecretAuthenOpts>
{
    public ClientSecretAuthenticationHandler(IOptionsMonitor<ClientSecretAuthenOpts> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) 
        : base(options, logger, encoder, clock) { }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // if there's no header for Client ID & Client Sercet, skip
        if(
            Context.Request.Headers.TryGetValue(Options.ApiClientIdHeadername, out var clientIdHeader) &&
            Context.Request.Headers.TryGetValue(Options.ApiClientTokenHeaderName, out var clientSecretHeader) 
        ){
            // validate client's id & secret
            var clientId = clientIdHeader.FirstOrDefault();
            var clientKey = clientSecretHeader.FirstOrDefault();
            var (valid, id) = await ValidateApiKeyAsync(clientId, clientKey);

            if(!valid){
                return AuthenticateResult.Fail($"invalid token:{clientKey}");
            }else{
                var principal = new ClaimsPrincipal(id);
                var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), this.Scheme.Name);
                return AuthenticateResult.Success(ticket);
            }
        }
        return AuthenticateResult.NoResult();
    }

    private Task<(bool, ClaimsIdentity)> ValidateApiKeyAsync(string clientId,string clientSecret)
    {
        ClaimsIdentity id = null;
        // fake: need check key against the Database or other service
        if(clientId=="Smith" && clientSecret == "top secret"){
            id = new ClaimsIdentity(
                new Claim[]{ 
                    new Claim(ClaimTypes.NameIdentifier, "client id from db or from the request"),
                    new Claim("Add Any Claim", "add the value as you like"),
                    // ... 
                }
                ,this.Scheme.Name
            );
            return Task.FromResult((true, id));
        }
        return Task.FromResult((false,id));
    }

}

测试

假设我们有一个带[Authorize]属性注释的控制器动作

[Authorize]
public IActionResult Privacy()
{
    return Ok("hello,world");
}

在浏览器(UI,不带标题)中访问URL时,如果用户未登录,则该用户将被重定向到Azure AD身份验证。

在使用客户机密测试上述请求时,

我们将收到“ hello,world”响应: 在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

带有ui.router的AngularJs如何为其子级设置身份验证

来自分类Dev

如何为基本的HTTP身份验证设置用户名和密码?

来自分类Dev

如何为Rails设置远程JSON API以进行身份验证和会话

来自分类Dev

如何为Rails设置远程JSON API进行身份验证和会话

来自分类Dev

如何为经过身份验证的 API GET 请求设置请求标头

来自分类Dev

如何为Solr设置dsetool身份验证?

来自分类Dev

如何为Windows SSH设置UNIX的密钥身份验证?

来自分类Dev

如何为基本身份验证配置Web Api 2和IIS?

来自分类Dev

如何为asp.net mvc和Web API实施相同的身份验证机制

来自分类Dev

Laravel Airlock如何针对未经身份验证的Web和API请求返回不同的响应

来自分类Dev

如何为Firebase身份验证用户设置自定义用户UID?

来自分类Dev

如何为包含的网址规则在入口中设置基本身份验证?

来自分类Dev

如何在pam策略中为不同的用户或组设置不同的身份验证要求?

来自分类Dev

如何在 pam 策略中为不同的用户或组设置不同的身份验证要求?

来自分类Dev

API和Python的身份验证

来自分类Dev

Azure API管理和身份验证

来自分类Dev

如何为基于证书的身份验证使用httr指定证书,密钥和根证书?

来自分类Dev

如何为Redis添加SSL代理和身份验证层

来自分类Dev

在Azure AD中如何为特定区域的用户进行身份验证和授权?

来自分类Dev

如何为Java Spring REST API实现AngularJS JWT身份验证

来自分类Dev

如何为移动应用程序创建API(需要身份验证)

来自分类Dev

经典的ASP xmlhttp获取如何为sendgrid api添加身份验证

来自分类Dev

如何为AWS Private API网关启用SAML身份验证

来自分类Dev

如何为移动应用程序创建API(需要身份验证)

来自分类Dev

API网关针对不同端点的不同身份验证机制

来自分类Dev

如何-AWS Rest API身份验证

来自分类Dev

为什么API网关和身份验证服务应该不同?

来自分类Dev

设置代理设置和代理身份验证

来自分类Dev

如何为docker push进行身份验证?

Related 相关文章

  1. 1

    带有ui.router的AngularJs如何为其子级设置身份验证

  2. 2

    如何为基本的HTTP身份验证设置用户名和密码?

  3. 3

    如何为Rails设置远程JSON API以进行身份验证和会话

  4. 4

    如何为Rails设置远程JSON API进行身份验证和会话

  5. 5

    如何为经过身份验证的 API GET 请求设置请求标头

  6. 6

    如何为Solr设置dsetool身份验证?

  7. 7

    如何为Windows SSH设置UNIX的密钥身份验证?

  8. 8

    如何为基本身份验证配置Web Api 2和IIS?

  9. 9

    如何为asp.net mvc和Web API实施相同的身份验证机制

  10. 10

    Laravel Airlock如何针对未经身份验证的Web和API请求返回不同的响应

  11. 11

    如何为Firebase身份验证用户设置自定义用户UID?

  12. 12

    如何为包含的网址规则在入口中设置基本身份验证?

  13. 13

    如何在pam策略中为不同的用户或组设置不同的身份验证要求?

  14. 14

    如何在 pam 策略中为不同的用户或组设置不同的身份验证要求?

  15. 15

    API和Python的身份验证

  16. 16

    Azure API管理和身份验证

  17. 17

    如何为基于证书的身份验证使用httr指定证书,密钥和根证书?

  18. 18

    如何为Redis添加SSL代理和身份验证层

  19. 19

    在Azure AD中如何为特定区域的用户进行身份验证和授权?

  20. 20

    如何为Java Spring REST API实现AngularJS JWT身份验证

  21. 21

    如何为移动应用程序创建API(需要身份验证)

  22. 22

    经典的ASP xmlhttp获取如何为sendgrid api添加身份验证

  23. 23

    如何为AWS Private API网关启用SAML身份验证

  24. 24

    如何为移动应用程序创建API(需要身份验证)

  25. 25

    API网关针对不同端点的不同身份验证机制

  26. 26

    如何-AWS Rest API身份验证

  27. 27

    为什么API网关和身份验证服务应该不同?

  28. 28

    设置代理设置和代理身份验证

  29. 29

    如何为docker push进行身份验证?

热门标签

归档