就在最近的一个小型业余项目中,我需要一种方法来向用户使用Azure AD登录后向其注入声明。具体来说,一些角色和其他与用户可以在应用程序中执行的操作有关的事情。

事实证明这很容易。这将是一篇简短的文章。

OpenID连接

可以在OnTokenValidated事件中添加自定义声明,如下所示:

services
    .AddAuthentication(o =>
    {
        o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        o.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect(o =>
    {
        //Additional config snipped
        o.Events = new OpenIdConnectEvents
        {
            OnTokenValidated = async ctx =>
            {
                //Get user's immutable object id from claims that came from Azure AD
                string oid = ctx.Principal.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");

                //Get EF context
                var db = ctx.HttpContext.RequestServices.GetRequiredService<AuthorizationDbContext>();

                //Check is user a super admin
                bool isSuperAdmin = await db.SuperAdmins.AnyAsync(a => a.ObjectId == oid);
                if (isSuperAdmin)
                {
                    //Add claim if they are
                    var claims = new List<Claim>
                    {
                        new Claim(ClaimTypes.Role, "superadmin")
                    };
                    var appIdentity = new ClaimsIdentity(claims);

                    ctx.Principal.AddIdentity(appIdentity);
                }
            }
        };
    });

在这里,我们:

  1. 从依赖项注入容器获取EF数据库上下文
  2. 使用它来尝试在表中查找用户
  3. 如果找到,则将超级管理员角色应用于他们

此后,所有现有的索赔仍然存在。我们仅添加新的声明。由于我们使用cookie身份验证作为登录方案,因此此新声明也将写入cookie。因此,它将在以后的所有请求中可用。

我在GitHub上为此制作了一个示例应用程序:https : //github.com/juunas11/CustomOidcClaims

智威汤逊

确实与以前类似,请看一下:

services
    .AddAuthentication(o =>
    {
        o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(o =>
    {
        //Additional config snipped
        o.Events = new JwtBearerEvents
        {
            OnTokenValidated = async ctx =>
            {
                //Get the calling app client id that came from the token produced by Azure AD
                string clientId = ctx.Principal.FindFirstValue("appid");

                //Get EF context
                var db = ctx.HttpContext.RequestServices.GetRequiredService<AuthorizationDbContext>();

                //Check if this app can read confidential items
                bool canReadConfidentialItems = await db.Applications.AnyAsync(a => a.ClientId == clientId && a.ReadConfidentialItems);
                if (canReadConfidentialItems)
                {
                    //Add claim if yes
                    var claims = new List<Claim>
                    {
                        new Claim("ConfidentialAccess", "true")
                    };
                    var appIdentity = new ClaimsIdentity(claims);

                    ctx.Principal.AddIdentity(appIdentity);
                }
            }
        };
    });

如果您需要解释所发生的情况,请查看OIDC上的上一部分:D

您可以在那里执行各种逻辑,并且可以访问DI以及HTTP上下文。

尽管如果在应用的所有部分中都不需要这些声明,则最好检查授权策略中的访问权限:)

不过,OnTokenValidated可以在JWT Bearer的每个请求上运行,因此,如果可以将声明包含在令牌中,那肯定更好!