C# .NET如果从OIDC提供的用户在数据库中不可用,如何不进行身份验证

C# .NET如果从OIDC提供的用户在数据库中不可用,如何不进行身份验证,c#,asp.net-core,openid-connect,C#,Asp.net Core,Openid Connect,因此,我的.NET核心Web应用程序正在通过Azure AD登录用户,我有一个包含用户及其角色的数据库 我已经创建了OIDC中间件,以便为尝试登录的用户从数据库中添加声明 因此,流程是: 我用我的广告帐号登录 我获取电子邮件地址并在数据库中检查其角色 现在,如果用户被阻止或未分配,登录应该失败 所以我的问题是:当用户在数据库中不可用或被阻止时,有没有办法拒绝用户的身份验证 我现在做的是,我设置了一个声明,如果该声明不可用,它将被重定向到“拒绝访问”页面(通过使用授权策略),但我希望用户将从M

因此,我的.NET核心Web应用程序正在通过Azure AD登录用户,我有一个包含用户及其角色的数据库

我已经创建了OIDC中间件,以便为尝试登录的用户从数据库中添加声明

因此,流程是:

  • 我用我的广告帐号登录
  • 我获取电子邮件地址并在数据库中检查其角色
  • 现在,如果用户被阻止或未分配,登录应该失败
所以我的问题是:当用户在数据库中不可用或被阻止时,有没有办法拒绝用户的身份验证

我现在做的是,我设置了一个声明,如果该声明不可用,它将被重定向到“拒绝访问”页面(通过使用授权策略),但我希望用户将从Microsoft/AD重定向到登录页面(最好是通过消息)

这有可能吗?如果有,怎么可能

这是我现在的代码:

 services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
     .AddAzureAD(options => { Configuration.Bind("AzureAd", options); }
 );

 services.AddControllersWithViews(options =>
 {
   var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .RequireAssertion(context =>
                {
                    Claim claim = context.User.Claims.First(claim => claim.Type == ClaimTypes.Expired);
                    return context.User.HasClaim(x => x.Type == ClaimTypes.Expired) &&
                           context.User.Claims.First(claim => claim.Type == ClaimTypes.Expired).Value
                               .Equals("false", StringComparison.OrdinalIgnoreCase);
                })
                .RequireClaim(ClaimTypes.Name)
                .RequireClaim(ClaimTypes.Role)
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        });

 // OIDC Middleware, to access the User's Claims while logging in through AzureAD
        services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
        {
            options.Events = new OpenIdConnectEvents
            {
                OnRemoteFailure = ctx =>
                {
                    ctx.Response.Redirect("/");
                    ctx.HandleResponse();
                    return Task.CompletedTask;
                },
                OnSignedOutCallbackRedirect = ctx =>
                {
                    ctx.Response.Redirect("/");
                    ctx.HandleResponse();
                    return Task.CompletedTask;
                },
                OnTokenValidated = ctx =>
                {
                    // Get the user's email 
                    var email = ctx.Principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;

                    // Query the database to get the role
                    using (var db = ctx.HttpContext.RequestServices.GetRequiredService<TracingContext>())
                    {
                        // Get the Users from the database, with the logged in email address (from Azure)
                        User user = db.Users.FirstOrDefault(u => u.UPN.Equals(email));

                        if (user != null)
                        {
                            user.LastLogin = DateTime.Now;
                            db.SaveChanges();

                            // Add claims
                            var claims = new List<Claim>
                            {
                                new Claim(ClaimTypes.Role, user.Role.ToString()),
                                new Claim(ClaimTypes.Expired, (!user.IsActivated || user.IsBlocked).ToString())
                            };

                            // Save the claim
                            var appIdentity = new ClaimsIdentity(claims);
                            ctx.Principal.AddIdentity(appIdentity);
                        }
                        else
                        {
                           **// Send back to Login Page (with error message, maybe?)**
                        }
                    }
                    return Task.CompletedTask;
                },
            };
        });
services.AddAuthentication(AzureAddFaults.AuthenticationScheme)
.AddAzureAD(选项=>{Configuration.Bind(“AzureAd”,选项);}
);
services.addcontrollerswithview(选项=>
{
var policy=new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()文件
.Requiremeartion(上下文=>
{
Claim=context.User.Claims.First(Claim=>Claim.Type==ClaimTypes.Expired);
返回context.User.HasClaim(x=>x.Type==ClaimTypes.Expired)&&
context.User.Claims.First(claim=>claim.Type==ClaimTypes.Expired).Value
.Equals(“false”,StringComparison.ordinallingorecase);
})
.RequimReclain(ClaimTypes.Name)
.RequimReclain(ClaimTypes.Role)
.Build();
options.Filters.Add(新的授权过滤器(策略));
});
//OIDC中间件,用于在通过AzureAD登录时访问用户声明
配置(AzureADDefaults.OpenIdScheme,选项=>
{
options.Events=新的OpenIdConnectEvents
{
OnRemoteFailure=ctx=>
{
ctx.Response.Redirect(“/”);
ctx.HandleResponse();
返回Task.CompletedTask;
},
OnSignedOutCallbackRedirect=ctx=>
{
ctx.Response.Redirect(“/”);
ctx.HandleResponse();
返回Task.CompletedTask;
},
OnTokenValidated=ctx=>
{
//获取用户的电子邮件
var email=ctx.Principal.Claims.FirstOrDefault(c=>c.Type==ClaimTypes.Name)?.Value;
//查询数据库以获取角色
使用(var db=ctx.HttpContext.RequestServices.GetRequiredService())
{
//使用登录的电子邮件地址(从Azure)从数据库获取用户
User User=db.Users.FirstOrDefault(u=>u.UPN.Equals(email));
如果(用户!=null)
{
user.LastLogin=DateTime.Now;
db.SaveChanges();
//添加索赔
var索赔=新列表
{
新声明(ClaimTypes.Role,user.Role.ToString()),
新声明(ClaimTypes.Expired,(!user.IsActivated | | | user.IsBlocked).ToString())
};
//保存索赔
var appIdentity=新的索赔实体(索赔);
ctx.委托人.额外性(appIdentity);
}
其他的
{
**//发送回登录页面(可能有错误消息?)**
}
}
返回Task.CompletedTask;
},
};
});

您可以覆盖默认处理并自行处理响应:

// Send back to Login Page (with error message, maybe?)
ctx.HandleResponse();
ctx.Response.Redirect("/path/to/login");

对的调用表示我们希望自己处理响应,下面的调用设置重定向。有几种方法可以发送错误消息。一种方法是为登录URL提供一个查询字符串参数。

我已经尝试过了,但我认为令牌不会被删除,因此它仍然登录no?在哪种情况下,我应该检查数据库中是否存在该用户?因为现在我在OnTokenValidated事件中执行此操作,但我认为此时用户已经登录,不是吗?此解决方案使用
OnTokenValidated
,就是执行此操作的方法。用户将登录到Azure AD租户,但不会登录到您的web应用程序。你需要在这里这样做,因为只有这样你才知道它是哪个用户。当我尝试这样做时,我在Microsoft登录页面中遇到了一个循环是的,那是因为你1。登录到AAD。2.返回应用程序的登录页面。3.这一次,您已登录,因此直接返回应用程序。4.被送回AAD。从3开始重复。您可能希望将用户发送回事件处理程序中的“拒绝访问”页面。如果AAD支持,此拒绝访问页面可允许用户注销AAD,然后使用其他帐户重试。