使用 Shibboleth 的 asp.net MVC 身份验证
Posted
技术标签:
【中文标题】使用 Shibboleth 的 asp.net MVC 身份验证【英文标题】:asp.net MVC authentication with Shibboleth 【发布时间】:2015-04-27 09:17:49 【问题描述】:Shibboleth 是作为“插件”添加到 IIS 的 SSO 身份验证。 用户完成登录后,会出现显示 Shibboleth 会话的标题: ShibSessionID ShibIdentityProvider eppn 联系 权利 无范围的从属关系 ...更多
所以我可以从标题中提取用户名和角色。 到目前为止一切顺利。
问题: 如何实现一个处理程序来读取标头并设置用户被授权的状态? 想法是使用 [授权] 属性和方法 角色.IsUserInRole。 全部来自标头,没有数据库,没有用户管理。
更新
根据@Pharylon 的回答实现
在本次更新中没有什么新内容,只是对副本和过去朋友的帮助。 当然,您必须根据您的 Shibboleth 设置调整属性和 Header 字段名。
文件:ShibbolethPrincipal.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal; //GenericPrincipal
namespace Shibboleth
public class ShibbolethPrincipal : GenericPrincipal
public string username
get return this.Identity.Name.Replace("@ksz.ch", "");
public string firstname
get return HttpContext.Current.Request.Headers["givenName"];
public string lastname
get return HttpContext.Current.Request.Headers["surname"];
public string phone
get return HttpContext.Current.Request.Headers["telephoneNumber"];
public string mobile
get return HttpContext.Current.Request.Headers["mobile"];
public string entitlement
get return HttpContext.Current.Request.Headers["eduzgEntitlement"];
public string homeOrganization
get return HttpContext.Current.Request.Headers["homeOrganization"];
public DateTime birthday
get
DateTime dtHappy = DateTime.MinValue;
try
dtHappy = DateTime.Parse(HttpContext.Current.Request.Headers["dateOfBirth"]);
finally
return dtHappy;
set
public ShibbolethPrincipal()
: base(new GenericIdentity(GetUserIdentityFromHeaders()), GetRolesFromHeader())
public static string GetUserIdentityFromHeaders()
//return HttpContext.Current.Request.Headers["eppn"];
return HttpContext.Current.Request.Headers["principalName"];
public static string[] GetRolesFromHeader()
string[] roles = null;
//string rolesheader = HttpContext.Current.Request.Headers["affiliation"];
string rolesheader = HttpContext.Current.Request.Headers["eduzgEntitlement"];
if (rolesheader != null)
roles = rolesheader.Split(';');
return roles;
文件:ShibbolethController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Shibboleth
public class ShibbolethController : Controller
protected new ShibbolethPrincipal User
get
return (base.User as ShibbolethPrincipal) ?? null; //CustomPrincipal.GetUnauthorizedPrincipal();
文件:Global.asax
void Application_PostAuthenticateRequest(object sender, EventArgs e)
var ctx = HttpContext.Current;
var principal = new ShibbolethPrincipal();
HttpContext.Current.User = principal;
使用例子:
namespace itservices.Controllers
[Authorize] //examples : [Authorize(Roles="Administrators")], [Authorize(Users="Alice,Bob")]
public class PasswordMailController : ShibbolethController
if(User.IsInRole("staff"))
【问题讨论】:
您是否尝试创建一个动作过滤器并在 OnActionExecuting 方法中进行此处理? msdn.microsoft.com/en-us/library/dd381609%28v=vs.100%29.aspx 我认为最好在开始处理请求时设置主体/身份,以便正常的授权过滤器和方法工作。 @RazvanDumitru - ActionFilters 执行 AFTER 授权过滤器,它们没有用 很高兴我能帮上忙。不过,我建议 ShibbolethController 的 User 永远不要返回 null 对象。您不希望 User.Identity.IsAuthenticated 引发异常 - 它应该是检查用户是否有效的可靠方法。此外,您应该在实例化时设置 Principal 的值(我喜欢将其设为不可变对象)。否则,如果你让单元测试不断调用 HttpContext.Current,你将很难进行单元测试。 你好法里伦。朱普,有道理。我也在为 UnauthorizedPrincipal 进行更改。谢谢 【参考方案1】:您需要在 Global.asax.cs 中创建一个具有以下签名的方法
protected void Application_PostAuthenticateRequest()
//Your code here.
这将在几乎所有其他操作完成之前自动调用(如果存在,MVC 将调用此方法,您不必在任何地方“打开”它),这是您需要设置 Principal 的地方。例如,假设您有一个名为 RolesHeader
的标头具有逗号分隔的角色值和另一个名为 UserId
的标头具有(duh)用户 ID。
您的代码,没有任何错误处理,可能看起来像:
protected void Application_PostAuthenticateRequest()
var rolesheader = Context.Request.Headers["RolesHeader"];
var userId = Context.Request.Headers["UserId"];
var roles = rolesheader.Split(',');
var principal = new GenericPrincipal(new GenericIdentity(userId), roles);
Context.User = principal;
[Authorize]
属性使用的是 Principal/Identity,因此在请求生命周期开始时将其设置在此处意味着 [Authorize]
属性将正常工作。
其余部分是可选的,但我推荐它:
我喜欢创建自己的自定义类来实现 IPrincipal 和 IIdentity,而不是使用 GenericPrincipal 和 GenericIdentity,因此我可以在其中填充更多用户信息。然后,我的自定义 Principal 和 Identity 对象具有更丰富的信息,例如分支机构编号或电子邮件地址等。
然后,我创建了一个名为 BaseController
的控制器,它具有以下内容
protected new CustomPrincipal User
get
return (base.User as CustomPrincipal) ?? CustomPrincipal.GetUnauthorizedPrincipal();
这允许我访问我所有丰富的自定义 Principal 数据,而不仅仅是 IPrincipal 中定义的数据。然后我所有的真实控制器都从BaseController
继承,而不是直接从Controller
继承。
显然,当使用这样的自定义主体时,在 Application_PostAuthenticateRequest() 方法中,您需要将 Context.User 设置为您的 CustomPrincipal
而不是 GenericPrincipal
。
【讨论】:
太棒了!这比我预期的要容易得多。我担心我必须实现 ExtendetMembershibProvider 和 RoleProvider。非常感谢以上是关于使用 Shibboleth 的 asp.net MVC 身份验证的主要内容,如果未能解决你的问题,请参考以下文章
将 WordPress iOS 应用程序与受 Shibboleth 保护的 WordPress 配合使用
使用 python 登录 SAML/Shibboleth 认证服务器