我们正在构建一个ASP.NET应用程序,并且要求使用公司LDAP系统(Siteminder)进行身份验证(上行:没有登录对话框)。角色在LDAP工具中创建,用户土地经理将用户分配给角色(阅读:必须易于理解结构)。目前,使用该系统的所有应用程序都使用双重输入流程,将应用程序中标识的角色手动输入LDAP系统并分配用户,然后在基于应用程序的控制面板中将应用程序功能分配给其角色镜像。这是有效的,但困扰我的是需要双重输入。
我想要实现的是应用程序查询LDAP系统以获取分配给应用程序的角色列表(在LDAP系统中标识)并使用它们填充角色:功能控制面板。这部分看起来非常简单。但是,在确定要在Authorize属性中输入的内容时,我会失去清晰度:
[Authorize(Roles = "Admin, Moderator")]
会变成什么?
[Authorize(LoadedRoles(r => r.FindAll("some expression that describes the roles that have a particular permission")))]
我在这里认真地进入蓝天领土。我从一个架构的角度阅读this question并且喜欢 - 建议将权限作为角色的答案。但是,对于需要管理用户的用户区管理员来说,这可能是不可接受的。另一方面,this question将事物转化为非字符串资源,但我无法想象如何将其转换为具有此类功能的角色"。
有什么建议吗?
更新
根据以下@venerik的建议,我取得了一些进展。目前,我已将所有内容封装在[AuthorizeFunctionAttribute]
中,并将各个部分分类到以后的所有位置。为此,我创建了三个变量:
private IList<KeyValuePair<long, string>> Roles;
private IList<KeyValuePair<long, string>> Functions;
private IList<RoleFunction> RoleFunctions;
...然后将静态数据放入其中:
Roles = new ICollection<KeyValuePair<long, string>>();
Roles.Add(KeyValuePair<long, string>(1, "Basic User"));
Roles.Add(KeyValuePair<long, string>(2, "Administrator"));
Functions = new ICollection<KeyValuePair<long, string>>();
Functions.Add(KeyValuePair<long,string>(1,"List Things"));
Functions.Add(KeyValuePair<long,string>(2,"Add Or Edit Things"));
Functions.Add(KeyValuePair<long,string>(3,"Delete Things"));
......最后将它们捆绑在一起(以复杂的方式为未来奠定基础):
RoleFunctions = new IList<RoleFunction>();
RoleFunctions.Add(
new RoleFunction
{
RoleId = Roles.Where( r => r.Value == "Basic User").FirstOrDefault().Key,
FunctionId = Functions.Where( f => f.Value == "List Things" ).FirstOrDefault().Key,
isAuthorized = true
},
new RoleFunction
{
RoleId = Roles.Where( r => r.Value == "Administrator").FirstOrDefault().Key,
FunctionId = Functions.Where( f => f.Value == "Add or Edit Things" ).FirstOrDefault().Key,
isAuthorized = true
},
// More binding...
);
到目前为止,我对此感到满意。所以我去研究AuthorizeCore看看我需要做什么。但是,根据页面底部的评论,它不是很有帮助。我或多或少得到了最后,该方法需要返回bool
值。我知道我需要检查其中一个User.Roles
数组是否符合通过[AuthorizeFunction("List Things")]
传入的权限。
更新(再次):
我已经获得了以下代码,看起来它可以满足我的需求(一种方法需要充实):
/// <summary>An authorization attribute that takes "function name" as a parameter
/// and checks to see if the logged-in user is authorized to use that function.
/// </summary>
public class AuthorizeFunctionAttribute : AuthorizeAttribute
{
private IList<KeyValuePair<long, string>> Roles;
private IList<KeyValuePair<long, string>> Functions;
private IList<RoleFunction> RoleFunctions;
public string Function { get; private set; }
public AuthorizeFunctionAttribute(string FunctionName)
{
Function = FunctionName;
Roles = SetApplicationRoles();
Functions = SetApplicationFunctions();
RoleFunctions = SetRoleFunctions();
}
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
bool userIsAuthorized = false;
foreach (string ur in GetUserRoles(httpContext.Current.Request.Headers["SM_USER"]))
{
long roleId = Roles.Where( sr => sr.Value == ur )
.First().Key;
long functionId = Functions.Where( sf => sf.Value == Function )
.First().Key;
// If any role is authorized for this function, set userIsAuthorized to true.
// DO NOT set userIsAuthorized to false within this loop.
if (RoleFunctions.Where(rf => rf.RoleId == roleId && rf.FunctionId == functionId)
.First().isAuthorized)
{
userIsAuthorized = true;
}
}
return userIsAuthorized;
}
以前我对创建自定义属性的基础知识不够了解,不能自行解决。但是,this MSDN article告诉我一开始应该对我来说显而易见的事情:自己构建它。所以,一旦我将GetUserRoles()
方法放在一起,我就应该开始了。
答案 0 :(得分:1)
我认为您可以使用自定义AuthorizeAttribute
解决此问题。在我工作的项目中,他们使用它来访问Active Directory(如this answer中所述)。
在你的情况下,它看起来像:
public class AuthorizeWithLDAPAttribute(string functionName) : AuthorizeAttribute
{
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
// check LDAP to verify that user has
// a role that's linked to `functionName`
}
}
接下来,您可以在控制器和/或方法上使用此属性:
[AuthorizeWithLDAP("functionName1")]
public class BlogController : Controller
{
....
[AuthorizeWithLDAP("functionName2")]
public ViewResult Index()
{
return View();
}
}
现在只有角色与functionName1
相关联的用户才能访问控制器,只有角色与functionName1
和functionName2