【问题标题】:Azure Active Directory for authentication and ASP.NET Core Identity for authorization用于身份验证的 Azure Active Directory 和用于授权的 ASP.NET Core Identity
【发布时间】:2018-05-18 11:48:21
【问题描述】:

我想创建一个 ASP.NET Core 2.0 应用程序,它使用 Azure Active Directory 作为身份提供者(用于身份验证)但 ASP.NET Core Identity 用于授权(例如,使用控制器属性,如 '[Authorize(Roles = "Admin") ]')。在解决方案中,我期望本地身份数据库表AspNetUserLogins to hold references to the Azure Active Directory identities

我认为解决方案将涉及claim transformation 使用从 ASP.NET Core Identity 获取的角色来装饰经过身份验证的用户。

我的问题:

  1. 我可以通过 Visual Studio 解决方案模板获得 Azure Active Directory 身份验证,但是我不知道如何在 Startup.ConfigureServices 中的某处添加和配置 ASP.NET Core 标识(例如 services.AddIdentity() 等())
  2. 我想知道正确的钩子在哪里进行声明转换。 (例如 OpenIdConnectEvents.OnTokenValidated 或 AccountController 方法)

重现我的基线的步骤...

  1. 在 portal.azure.com...

    • Azure Active Directory > 应用注册 > 新应用注册(您可以稍后删除)
    • 为应用程序命名并将其设置为“Wep 应用程序/API”
    • 将“登录 URL”设置为 something arbitrary like 'https://blabla'
    • 转到新创建的应用注册并复制“应用程序 ID”
  2. 使用 Visual Studio 2017 15.4.2 创建 ASP.NET Core 2.0 项目...

    • ASP.NET Core Web 应用程序
    • .NET Framework、ASP.NET Core 2.0、“Web 应用程序”
    • 更改身份验证>“工作或学校帐户”
    • 选择“云 - 单一组织”
    • 输入您的域“something.onmicrosoft.com”(我猜)
    • 点击向导创建项目
    • 编辑 appsettings.json 并将“ClientId”更改为“应用程序 ID”(从 portal.azure.com 复制)
    • 复制为“CallbackPath”设置的值(例如“/signin-oidc”)
    • 转到项目属性 > 调试 > 并复制 IIS Express https url(例如 'https://localhost:44366/')
    • 切换回 portal.azure.com 中的新应用注册
    • 'Reply URLs' > 从上述两条信息的串联中添加一个新的回复 URL(例如 'https://localhost:44366/signin-oidc')
    • 点击“保存”
    • 在 Visual Studio 中运行项目
    • 使用您的 Azure Active Directory 帐户登录(系统会要求您同意应用所需的权限)
    • 然后您应该会看到 ASP.NET Core 演示页面

我从这里不太确定......

(我从模板生成的解决方案中借用代码,将“身份验证选项”设置为“个人用户帐户”>“在应用程序中存储用户帐户”。)

  • 添加 nuget 包 Microsoft.AspNetCore.Identity.EntityFrameworkCore(我必须先将 Microsoft.AspNetCore.Authentication.Cookies 从 2.0.0 升级到 2.0.1 才能安装)
  • 添加 nuget 包 Microsoft.EntityFrameworkCore.SqlServer
  • 添加以下类

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext(DbContextOptions<AspNetCoreIdentity.Data.ApplicationDbContext> options) : base(options)
        {
        }
    
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
        }
    }
    
    public class ApplicationUser : IdentityUser
    {
    }
    
  • 在 Startup.ConfigureServices() 开头添加以下内容

    services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
    
  • 将连接字符串添加到 appsettings.json(假定本地主机上的默认 SQL Server 实例和名为“AspNetCoreIdentity”的身份数据库)

    "ConnectionStrings": {
      "DefaultConnection": "Data Source=.\\;Initial Catalog=AspNetCoreIdentity;Integrated Security=True;MultipleActiveResultSets=True"
    }
    

现在,当我再次运行该应用程序时,我最终进入了一个重定向循环,我认为该循环在我的应用程序和 Azure Active Directory 登录之间运行。跟踪显示...

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed for user: (null). Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker: Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.

然后我尝试向 AccountController (Login, ExternalLogin) 添加方法,希望我可以打断点,但现在我真的卡住了。

其他参考资料...

【问题讨论】:

  • 您已经有解决方案了吗?
  • 显然今天是我们都来这里寻求答案的日子。运气好的话?哈哈。
  • 我还是没有办法解决这个问题。
  • 从 Identity 模板开始,然后模仿添加 Facebook auth 的说明会更容易,但在 OpenIdConnect 中添加

标签: asp.net-core asp.net-core-2.0


【解决方案1】:

我认为我有这个工作,但我对这个框架很陌生,所以欢迎对这个方法提出批评。

在启动时,我必须在 Microsoft 的示例中添加两件事。

  1. 将 DefaultSignInScheme 值设置为 AuthenticationProperties 以防止在授权失败时出现 Stackoverflow 异常(请参阅here)。
  2. 将拒绝访问路径添加到应用程序 cookie

Startup.cs:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddAzureAd(options => Configuration.Bind("AzureAd", options))
        .AddCookie(options =>
        {
            options.AccessDeniedPath = "/AccessDenied";
        });
   // Remaining code removed

然后我扩展了 AzureAdAuthenticationBuilderExtensions > ConfigureAzureOptions 类并在令牌验证事件发生时做一些额外的工作(即从任何角色存储加载用户角色)

AzureAdAuthenticationBuilderExtensions.cs

public void Configure(string name, OpenIdConnectOptions options)
        {
            options.ClientId = _azureOptions.ClientId;
            options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
            options.UseTokenLifetime = true;
            options.CallbackPath = _azureOptions.CallbackPath;
            options.RequireHttpsMetadata = false;

            options.Events = new OpenIdConnectEvents
            {                    
                OnTokenValidated = (context) =>
                {                           
                    // Load roles from role store here
                    var roles = new List<string>() { "Admin" };
                    var claims = new List<Claim>();
                    foreach (var role in roles) claims.Add(new Claim(ClaimTypes.Role, role));

                    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                    context.Principal.AddIdentity(claimsIdentity);

                    return Task.CompletedTask;       
                }                    
            };
        }

【讨论】:

    猜你喜欢
    • 2015-10-18
    • 2016-01-19
    • 2022-06-13
    • 2021-12-09
    • 2022-10-04
    • 1970-01-01
    • 1970-01-01
    • 2022-12-22
    • 1970-01-01
    相关资源
    最近更新 更多