IdentityServer3 在身份服务器应用程序中的自定义 MVC 控制器中授权

IdentityServer3 Authorize in custom MVC controller in identity server application

我有一个用于 SSO 的 Identity Server 3 应用程序。在 IdentityServer 是 运行 的同一个应用程序中,我集成了 Asp.Net MVC 控制器用于用户注册等。但是我有一些没有特定角色就无法访问的方法,我想使用 Authorize 属性来进行角色检查。

根据此 GitHub 线程 https://github.com/IdentityServer/IdentityServer3/issues/1148 我已将所述控制器设置为使用与 IdentityServer 相同的基本路由,以便进入 Owin 管道。

在线程中有一个属性片段,它通常可以满足我的要求。它对用户进行身份验证并获得他们的一些声明,但问题是缺少许多声明 - 例如角色声明,我需要它才能使 Authorize 属性起作用。我花了很多时间试图了解为什么缺少声明,并且真的想避免查询数据库并自己添加它们。

在我的普通客户端应用程序中,我在 ClaimsPrincipal 中获得的声明是 (iss,aud,exp,nbf,nonce,iat,sid,sub,auth_time,idp,preferred_username,email ,email_verified,角色,网站,amr)。正如您将看到的,除了 sub 和 amr,其他声明与我在 IdentityServerFullLoginAttribute(下面的代码)的帮助下在 IdentitySever 应用程序中获得的声明完全不同。

问题是甚至有可能,为什么只检索这些声明(sub、name、amr、idp、auth_time、security_stamp)?

这是我的 IdentityServer 配置:

coreApp.UseIdentityServer(new IdentityServerOptions
            {
                Factory = factory,
                SigningCertificate = signingCertificate,
                SiteName = "Sitename",
                RequireSsl = true,
                LoggingOptions = new LoggingOptions
                {
                    EnableKatanaLogging = true
                },
                EventsOptions = new EventsOptions
                {
                    RaiseFailureEvents = true,
                    RaiseInformationEvents = true,
                    RaiseSuccessEvents = true,
                    RaiseErrorEvents = true
                },
                CspOptions = new CspOptions
                {
                    Enabled = true,
                    ScriptSrc = "'unsafe-eval' 'unsafe-inline'"
                }
            });
        });

这是我用来允许用户进行身份验证的上述属性

public abstract class OwinAuthenticationAttribute : FilterAttribute, IAuthenticationFilter
{
    public string AuthenticationType { get; set; }

    protected OwinAuthenticationAttribute(string authenticationType)
    {
        if (String.IsNullOrWhiteSpace(authenticationType)) throw new ArgumentNullException("authenticationType");

        AuthenticationType = authenticationType;
    }

    public virtual void OnAuthentication(AuthenticationContext filterContext)
    {
        var ctx = filterContext.HttpContext.Request.GetOwinContext();
        var result = AsyncHelper.RunSync(() => ctx.Authentication.AuthenticateAsync(AuthenticationType));
        if (result != null &&
            result.Identity != null &&
            result.Identity.IsAuthenticated)
        {
            filterContext.Principal = new ClaimsPrincipal(result.Identity);
        }
    }

    public abstract void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
}

public class IdentityServerFullLoginAttribute : OwinAuthenticationAttribute
{
    public IdentityServerFullLoginAttribute()
        : base(Constants.PrimaryAuthenticationType)
    {
        this.Order = 1;
    }

    public override void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    {
        var statusCodeResult = filterContext.Result as HttpStatusCodeResult;
        if (statusCodeResult != null && statusCodeResult.StatusCode == 401)
        {
            var ctx = filterContext.HttpContext.Request.GetOwinContext();
            var url = ctx.Environment.CreateSignInRequest(new SignInMessage
            {
                ReturnUrl = filterContext.HttpContext.Request.Url.AbsoluteUri
            });
            filterContext.Result = new RedirectResult(url);
        }
    }
}

这是控制器操作:

    [HttpGet]
    [Route("core/test/test")]
    [IdentityServerFullLogin]
    [Authorize(Roles = "Administrator")]
    public EmptyResult Test(string signin)
    {
        //return Redirect("~/core/" + IdentityServer3.Core.Constants.RoutePaths.Login + "?signin=" + signin);

        return new EmptyResult();
    }

好的,经过一番努力,我设法将一些东西放在一起来完成这项工作。 我正在 OwinAuthenticationAttribute 的 OnAuthentication() 中检索所需的声明,如下所示:

            var userManager = ctx.GetUserManager<ApplicationUserManager>();
            string sub = result.Identity.FindFirst("sub")?.Value;

            if (userManager.SupportsUserClaim)
            {
                result.Identity.AddClaims(await userManager.GetClaimsAsync(sub));
            }

            if (userManager.SupportsUserRole)
            {
                IList<string> roles = await userManager.GetRolesAsync(sub);

                foreach (string roleName in roles)
                {
                    result.Identity.AddClaim(new Claim(IdentityServer3.Core.Constants.ClaimTypes.Role, roleName, ClaimValueTypes.String));
                }
            }