我正在使用自定义角色提供程序开发MVC 5应用程序,但似乎AuthorizeAttribute从不调用我的客户角色提供程序,我的代码如下:
我的客户提供商:
namespace MyDomain
{
public class CustomRoleProvider : RoleProvider
{
public override string[] GetRolesForUser(string username)
{
using (MyContext objContext = new MyContext())
{
var objUser = objContext.Users.FirstOrDefault(x => x.Username == username);
if (objUser == null)
{
return null;
}
else
{
string[] ret = { objUser.Access_Levels.Name };
return ret;
}
}
}
public override bool IsUserInRole(string username, string roleName)
{
var userRoles = GetRolesForUser(username);
return userRoles.Contains(roleName);
}
}
我的控制器:
[Authorize(Roles = "Administrator")]
public class AdminController : Controller
和Web.Config:
<system.web>
<roleManager defaultProvider="CustomRoleProvider" enabled="true" >
<providers>
<clear />
<add name="CustomRoleProvider" type="Online_Storage_Portal.CustomRoleProvider" cacheTimeoutInMinutes="30"/>
</providers>
</roleManager>
</system.web>
此外,我的自定义角色提供程序与我的其他控制器位于同一项目中,我可以使用控制器中的以下代码调用我的自定义角色提供程序方法
String [] roles = Roles.GetRolesForUser(username)
但是[Authorize(Roles =“Administrator”)]的控制器总是将页面重定向到登录屏幕,即使用户登录和角色都是有价值的。
请帮助!!
答案 0 :(得分:2)
我相信我找到了问题的根源。我将假设您正在使用Windows身份验证,并尝试使用自定义角色提供程序代替自动加载的Windows组。查看MVC AuthorizeAttribute源代码,您会发现它实际上正在调用Principal.IsInRole。每个MSDN:
InRole首先检查IsRoleListCached属性,以确定当前用户的角色名称的缓存列表是否可用。如果IsRoleListCached属性为true,则检查高速缓存的列表以查找指定的角色。如果IsInRole方法在缓存列表中找到指定的角色,则返回true。 如果IsInRole找不到指定的角色,则会调用默认Provider实例的GetRolesForUser方法,以确定用户名是否与配置的ApplicationName值的数据源中的角色相关联。
所以我猜测因为Principal是Windows Principal,它的角色是填充和缓存的。当IsInRole被调用时,它会说'嘿,我已经有了角色,为什么我会回到提供者那里再次获得它们?“
你可以做的事情就是这样:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
WindowsIdentity identity = HttpContext.Current.Request.LogonUserIdentity;
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new GenericIdentity(identity.Name), Roles.GetRolesForUser());
}
这将从HttpContext中提取Windows标识,使用该名称从您的自定义提供程序显式获取角色,然后在请求上打一个新的GenericPrincipal。我进一步实现了一些逻辑来将角色存储在加密的cookie中,因此我们不必在每个请求上都使用角色提供程序。
void Application_PostAuthenticateRequest()
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
FormsAuthenticationTicket authTicket;
if (authCookie == null || authCookie.Value == "")
{
string[] getRoles = Roles.GetRolesForUser();
authTicket = new FormsAuthenticationTicket(1,
User.Identity.Name,
DateTime.Now,
DateTime.Now.AddMinutes(20),
true,
String.Join(";", getRoles));
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Current.Response.Cookies.Add(authCookie);
}
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch
{
return;
}
string[] roles = authTicket.UserData.Split(';');
if (Context.User != null)
Context.User = new System.Security.Principal.GenericPrincipal(Context.User.Identity, roles);
}