首页 文章

Aps .net IdentityServer4授权

提问于
浏览
0

我使用带有asp .net身份的IdentityServer4作为身份验证点 . 我的API / WebApps调用身份服务器来获取访问令牌 .

现在,如何在我的api / app控制器中的某些操作或内部操作之前授权使用?

我可以添加角色来访问令牌,然后在控制器中(在web api / web app中)使用AuthorizeAttribute并检查用户是否为IsInRole .

但这意味着如果我将更改用户角色,他将在注销登录后看到它(因为角色是访问令牌的一部分)或令牌必须到期 .

我想在每次需要授权他进行某些操作时(特别是对修改/删除某些数据的操作)询问身份服务器有关用户角色的信息 .

问怎么样?或者我需要寻找什么?

1 回答

  • 0

    所以这里有一些可能的解决方案:

    • 调用OIDC UserInfo endpoints 以获取每个请求的更新用户声明

    • 降低cookie生命周期以更频繁地自动刷新用户信息

    • 在IdentityServer上实现自定义 endpoints ,以便将配置文件更改信息发布到已订阅客户端列表(例如您的webapp) .

    • 在更改用户配置文件数据时,让IdentityServer强制单一注销

    就实施难度而言,降低cookie生命周期是最简单的(只是更改cookie过期),但它不保证最新的声明,并且它对用户可见(频繁重定向到IdentityServer,尽管没有登录是如果访问令牌生存期仍然有效,则为必需)

    让webapp在每个请求上调用UserInfo endpoints 是下一个最简单的(参见下面的示例),但性能影响最差 . 每个请求都将生成到IdentityServer的往返 .

    endpoints /订户模型将具有最低的性能开销 . 仅当用户配置文件信息实际更改时,才会发生对IdentityServer的UserInfo请求 . 实现起来会有点复杂:

    • 在IdentityServer项目中,您需要修改对配置文件数据的更改,并将http消息发布到您的webapp . 该消息可以只包含修改后的用户的用户ID . 此消息需要以某种方式进行身份验证,以防止恶意用户排除合法用户会话 . 您可以为此包含ClientCredentials承载令牌 .

    • 您的网络应用程序需要接收并验证邮件 . 它需要将更改后的用户ID存储在OnValidatePrincipal委托可访问的位置(最有可能通过DI容器中的服务)

    • 然后,Cookie OnValidatePrincipal委托将注入此本地服务,以在验证主体之前检查用户信息是否已更改

    Code Samples

    在每次调用时从 endpoints 获取更新的UserInfo

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationScheme = "NameOfYourCookieAuthSchemeHere",
        Events = new CookieAuthenticationEvents()
        {
            OnValidatePrincipal = async context =>
            {
                // Get updated UserInfo from IdentityServer
                var accessToken = context.Principal.Claims.FirstOrDefault(c => c.Type == "access_token").Value;
                var userInfoClient = new UserInfoClient("https://{IdentityServerUrlGoesHere}");
                var userInfoResponse = await userInfoClient.GetAsync(accessToken);
    
                // Invalidate Principal if Error Response
                if (userInfoResponse.IsError)
                {
                    context.RejectPrincipal();
                    await context.HttpContext.Authentication.SignOutAsync("NameOfYourCookieAuthSchemeHere");
                }
                else
                {
                    // Check if claims changed
                    var claimsChanged = userInfoResponse.Claims.Except(context.Principal.Claims).Any();
                    if (claimsChanged)
                    {
                        // Update claims and replace principal
                        var newIdentity = context.Principal.Identity as ClaimsIdentity;
                        newIdentity.AddClaims(userInfoResponse.Claims);
                        var updatedPrincipal = new ClaimsPrincipal();
                        context.ReplacePrincipal(updatedPrincipal);
                        context.ShouldRenew = true;
                    }
                }
            }
        }
    });
    

    从IdentityServer更新订阅的更改消息 . 此示例假设您已创建一个服务(例如IUserChangedService),该服务存储从IdentityServer endpoints 接收的userIds . 我没有webapp的接收 endpoints 或服务的示例 .

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationScheme = "NameOfYourCookieAuthSchemeHere",
        Events = new CookieAuthenticationEvents()
        {
            OnValidatePrincipal = async context =>
            {
                // Get User ID
                var userId = context.Principal.Claims.FirstOrDefault(c => c.Type == "UserIdClaimTypeHere");
    
                var userChangedService = context.HttpContext.RequestServices.GetRequiredService<IUserChangedService>();
                var userChanged = await userChangedService.HasUserChanged(userId);
    
                if (userChanged)
                {
                    // Make call to UserInfoEndpoint and update ClaimsPrincipal here. See example above for details
                }
            }
        }
    });
    

    除了使用本地数据库之外,asp.net核心文档也有这样的例子 . 连接到OnValidatePrincipal方法的方法是相同的:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie#reacting-to-back-end-changes

    希望这可以帮助!

相关问题