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));
}
}
我有一个用于 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));
}
}