拦截asp.net core Authorize action,授权成功后执行自定义动作

Posted

技术标签:

【中文标题】拦截asp.net core Authorize action,授权成功后执行自定义动作【英文标题】:Intercept asp.net core Authorize action to perform custom action upon successful authorization 【发布时间】:2018-09-16 08:02:18 【问题描述】:

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

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

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

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

            );

    

... []

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

【问题讨论】:

【参考方案1】:

OpenIDConnectOptions 类有一个 Events 属性,用于此类场景。这个Events 属性(OpenIdConnectEvents) 有一个OnTokenValidated 属性(Func<TokenValidatedContext, Task>),您可以覆盖它以便在验证令牌时收到通知。这是一些代码:

options.Events.OnTokenValidated = ctx =>

    // Your code here.
    return Task.CompletedTask;
;

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

正如@Brad 在 cmets 中提到的,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),正如我在代码中用注释调用的那样。

【讨论】:

OnUserInformationReceived 事件更适合 OP 的需求。它在成功登录时执行一次。您提供的事件会在每个请求上执行。 如果您使用的是 Azure B2C,那么此答案显示了如何访问 OIDC 事件:***.com/a/58515372/2608

以上是关于拦截asp.net core Authorize action,授权成功后执行自定义动作的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core JWT 身份验证以保护 webAPI [Authorize] 属性错误 401 Unauthorized

ASP.NET Core Authorize 属性不适用于 JWT

ASP.NET Core 2:使用 [Authorize] 对 API 的 Ajax 调用使预检请求失败

在 ASP.NET Core Identity 中使用 Authorize 属性检查多个策略之一

如何在无视图 WebAPI ASP.NET Core 应用程序中使用 [Authorize] 和防伪?

如何创建不依赖于 ASP.NET Core 声明的自定义 Authorize 属性?