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

egm*_*frs 2 c# asp.net-mvc asp.net-core identityserver4 asp.net-core-middleware

我的网络应用控制器上有[授权]属性,因此任何端点命中都会确保用户首先被重定向到登录OAuth服务器(如果尚未登录).

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

我得到了一个线索,它涉及添加自定义中间件.

我的启动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;

            });

    }

... []
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:我需要添加哪些代码,以及在何处调用将包含自定义操作的方法?

Kir*_*kin 6

该OpenIDConnectOptions班有一个Events特性,那就是用于这样的场景.这个Eventsproperty(OpenIdConnectEvents)有一个OnTokenValidatedproperty(Func<TokenValidatedContext, Task>),你可以覆盖它,以便在一个令牌被验证时得到通知.这是一些代码:

options.Events.OnTokenValidated = ctx =>
{
    // Your code here.
    return Task.CompletedTask;
};
Run Code Online (Sandbox Code Playgroud)

在示例代码中,ctx是a TokenValidatedContext,最终包含Principalproperty(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;
};
Run Code Online (Sandbox Code Playgroud)

ctx在这个例子中是一个UserInformationReceivedContext:它仍然包含Principal属性,但也有一个Userproperty(JObject),因为我在代码中调用了注释.