拦截 asp.net 核心授权操作,授权成功后执行自定义操作

Intercept asp.net core Authorize action to perform custom action upon successful authorization

我的 Web 应用程序控制器上有一个 [Authorize] 属性,因此任何端点命中都会确保用户被重定向到首先登录 OAuth 服务器(如果尚未登录。)

我现在想在每次用户登录时开始将用户声明写入 Web 应用程序数据库。为此,我需要在每次用户成功登录/授权时在 Web 应用程序上运行一些代码.

我得到的线索是它涉及添加自定义中间件。

我的Startup ConfigureServices代码目前如下:

public class Startup
{
    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        Configuration = configuration;
        Env = env;
    }

    public IHostingEnvironment Env { get; }
    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        services.AddMvc();

        // Adds a default in-memory implementation of IDistributedCache.
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            options.Cookie.HttpOnly = true;
        });

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
            .AddCookie()
            .AddOpenIdConnect(options =>
            {
                options.SignInScheme = "Cookies";
                options.Authority = Configuration["auth:oidc:authority"];                    

                options.RequireHttpsMetadata = !Env.IsDevelopment();
                options.ClientId = Configuration["auth:oidc:clientid"];
                options.ClientSecret = Configuration["auth:oidc:clientsecret"];
                options.ResponseType = "code id_token"; 

                options.Scope.Add(Configuration["auth:oidc:clientid"]);
                options.Scope.Add("offline_access");

                options.GetClaimsFromUserInfoEndpoint = true;
                options.SaveTokens = true;

            });

    }

... []

所以我的问题是:我需要添加什么代码以及在哪里添加,以便调用包含我的自定义操作的方法?

OpenIDConnectOptions class has an Events property, that is intended for scenarios like this. This Events property (OpenIdConnectEvents) has an OnTokenValidated 属性 (Func<TokenValidatedContext, Task>),您可以覆盖它以便在验证令牌时收到通知。这是一些代码:

options.Events.OnTokenValidated = ctx =>
{
    // Your code here.
    return Task.CompletedTask;
};

在示例代码中,ctx是一个TokenValidatedContext, which ultimately包含一个Principal 属性(ClaimsPrincipal):你应该可以使用这个属性 来获取您需要使用的声明等,例如ctx.Principal.FindFirst(...).

正如@Brad 在评论中提到的那样,每个请求都会调用 OnTokenValidated 并且(根据您自己的评论),将不包含您需要的 UserInfo。为了得到它,你可以使用 OnUserInformationReceived,像这样:

options.Events.OnUserInformationReceived = ctx =>
{
    // Here, ctx.User is a JObject that should include the UserInfo you need.
    return Task.CompletedTask;
};

ctx 在这个例子中是一个 UserInformationReceivedContext:它仍然包括 Principal 属性 但也有一个 User 属性 ( JObject),正如我在代码中用注释指出的那样。