我在一个项目中使用 asp.net mvc 4 和 entity framework 5。我有一个基础实体,所有实体都从它派生:
public abstract class BaseEntity
{
[Required]
public virtual int Id { get; set; }
[Required]
public virtual DateTime CreatedOn { set; get; }
public virtual string CreatedBy { set; get; }
[Required]
public virtual DateTime ModifiedOn { set; get; }
public virtual string ModifiedBy { set; get; }
}
首先,Account Entity 是应用程序用户的一个类:
public class Account : BaseEntity
{
public string UserName { get; set; }
public string Password { get; set; }
public byte[] AvatarBinary { get; set; }
public string AvatarMimeType { get; set; }
public virtual IList<AccountInRole> AccountRoles { get; set; }
}
用户角色:
public class Role : BaseEntity
{
public string RoleName { get; set; }
public virtual IList<AccountInRole> AccountRoles { get; set; }
}
每个用户可以有多个角色,反之亦然:
public class AccountInRole : BaseEntity
{
public int AccountId { get; set; }
public int RoleId { get; set; }
public virtual Account Account { get; set; }
public virtual Role Role { get; set; }
}
当我想为特定用户赋予角色时,请在 Accountrepository 中调用GetRoles方法。这是以这种方式实现的:
public class AccountRepository : IAccountRepository
{
#region Properties
private CharityContext DataContext { get; set; }
public IQueryable<Account> Accounts
{
get { return DataContext.Accounts; }
}
#endregion
#region Ctors
public AccountRepository() : this(new CharityContext())
{
}
public AccountRepository(CharityContext db)
{
DataContext = db;
}
#endregion
#region Methods
public List<Role> GetRoles(string userName)
{
var acc = DataContext.Accounts;
var query = from u in DataContext.Accounts
from r in DataContext.Roles
from ur in DataContext.AccountInRoles
where ur.AccountId == u.Id && ur.RoleId == r.Id && u.UserName == userName
select r;
return query.ToList();
}
#endregion
}
在此方法中,当编译器要在上面运行 LINQ 查询时引发了异常。这个例外是:
StackOverflowException 未处理
mscorlib.dll 中出现“System.StackOverflowException”类型的未处理异常
{无法计算表达式,因为当前线程处于堆栈溢出状态。}
GetRoles 方法被调用两次:
一次来自自定义授权属性:
public class CustomAuthorize : AuthorizeAttribute
{
//private readonly IAccountRepository _accountRepository;
private string[] roles;
//public CustomAuthorize(params string[] roles)
//{
// this.roles = roles;
//}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
if (!httpContext.User.Identity.IsAuthenticated)
return false;
if (Roles == string.Empty)
return true;
var lstRoles = Roles.Split(',');
AccountRepository _accountRepository = new AccountRepository();
var userRoles = _accountRepository.GetRoles(httpContext.User.Identity.Name);
foreach (var role in lstRoles)
{
bool isFound = false;
foreach (var userRole in userRoles)
{
if (userRole.RoleName == role)
isFound = true;
}
if (!isFound) return false;
}
return true;
}
}
第二次来自 Global.asax.cs 中的 Application_AuthenticateRequest 方法:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
string cookie = FormsAuthentication.FormsCookieName;
HttpCookie httpCookie = Request.Cookies[cookie];
if (httpCookie == null) return;
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(httpCookie.Value);
if(ticket == null || ticket.Expired) return;
FormsIdentity identity = new FormsIdentity(ticket);
var _accountRepository = new AccountRepository();
var roles = _accountRepository.GetRoles(identity.Name);
var principal = new CharityAccount(identity.Name, roles.Select(x => x.RoleName).ToArray());
Context.User = Thread.CurrentPrincipal = principal;
}
您可以在上面的方法中看到它的 CharityAccount 是这样实现的:
public class CharityAccount : IPrincipal
{
private string[] roles;
private IIdentity identity;
public IIdentity Identity
{
get { return identity; }
}
public bool IsInRole(string role)
{
return Array.IndexOf(roles, role) >= 0;
}
public CharityAccount(String name, String[] roles)
{
identity = new GenericIdentity(name, "Custom authentication");
this.roles = roles;
}
}
按照你的想法,问题出在哪里?问候