Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于声明的表单身份验证角色_C#_Asp.net Mvc 3_Asp.net Mvc 4 - Fatal编程技术网

C# 基于声明的表单身份验证角色

C# 基于声明的表单身份验证角色,c#,asp.net-mvc-3,asp.net-mvc-4,C#,Asp.net Mvc 3,Asp.net Mvc 4,我正在尝试使用MVC4中的forms身份验证对用户进行身份验证(我使用的是RavenDB,因此无法使用标准的成员资格提供程序)。然后,稍后我将使用User.IsInRole()方法或AuthorizeAttribute来验证用户是否担任员工角色 在这里,我设置了成功身份验证的票证(此时在UserController.cs): 在这里,我检查每个请求的票证(Global.asax): 如果我在其中一个操作方法(CalendarController.cs)上放置调试点,我会得到isStaffequa

我正在尝试使用MVC4中的forms身份验证对用户进行身份验证(我使用的是RavenDB,因此无法使用标准的成员资格提供程序)。然后,稍后我将使用
User.IsInRole()
方法或
AuthorizeAttribute
来验证用户是否担任员工角色

在这里,我设置了成功身份验证的票证(此时在
UserController.cs
):

在这里,我检查每个请求的票证(
Global.asax
):

如果我在其中一个操作方法(CalendarController.cs)上放置调试点,我会得到
isStaff
equals
false

public ActionResult Index()
{
    var user = HttpContext.User;

    bool isStaff = user.IsInRole(Role.Staff);

    return View();
}
只是为了完成(Roles.cs,只是一个测试东西的临时类):


有人能帮我指出我可能遗漏了什么吗?当我使用操作方法时,我设置的角色似乎正在消失。

您没有创建表单身份验证票证插入角色信息:

        var ticket = new FormsAuthenticationTicket(
                1, //ticket version
                userName,
                DateTime.Now,
                DateTime.Now.Add(timeout), //timeout
                true, //persistent cookies
                roles,// <---ROLES not model.Email
                FormsAuthentication.FormsCookiePath);
var ticket=新表单身份验证ticket(
1,//票证版本
用户名,
日期时间,现在,
DateTime.Now.Add(超时),//超时
true,//持久cookie

角色,//由于您使用的是Raven,我假设您创建了自己的自定义MembershipProvider和RoleProvider;并修改了web.config以使用它们。您应该有一个类似于以下内容的条目:

<membership defaultProvider="MyMembershipProvider">
  <providers>
    <add name="MyMembershipProvider" type="namespace.MyMembershipProvider, providerAssemblyName" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
  </providers>
</membership>
<roleManager enabled="true" defaultProvider="DefaultRoleProvider">
  <providers>
    <add connectionStringName="DefaultConnection" applicationName="/" name="DefaultRoleProvider" type="namespace.MyRoleProvider, providerAssemblyName" />
  </providers>
</roleManager>
如果您的成员资格和角色提供程序设置正确,ASP.NET应使用它们填充ClaimsPrincipal中的角色,然后在您选中IsInRole时检查声明

您还可以从ClaimsPrincipal中检索此类角色的角色

principal.FindAll(ClaimTypes.Role).Select(p => p.Value);
List<Claim> claims = new List<Claim>();
foreach (string role in roles)
   claims.Add(new Claim(ClaimTypes.Role, role));
ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Forms"));
FormsAuthentication.SetAuthCookie(username, false);
您可以像这样向ClaimsPrincipal添加角色

principal.FindAll(ClaimTypes.Role).Select(p => p.Value);
List<Claim> claims = new List<Claim>();
foreach (string role in roles)
   claims.Add(new Claim(ClaimTypes.Role, role));
ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Forms"));
FormsAuthentication.SetAuthCookie(username, false);

感谢大家帮我做这件事,我的想法(包括下面)非常好!如果用户有有效的票据(cookie),它会直接通过登录屏幕自动登录用户并且还使用
ClaimsIdentity
ClaimsPrincipal
对象处理基于声明的角色,而无需将角色放入用户的cookie中。它还处理
Global.asax.cs
文件中的身份验证,而无需输入自定义授权属性

UserController.cs

Global.asax.cs


您确定此参数适用于用户角色吗?在MSDN文档中,他们将此参数定义为“与票据一起存储的用户特定数据”。我在其他地方看到了此示例,我不希望将用户角色存储在票据中(最终在客户端上形成加密cookie)如果你想使用CordEx.U.IsInPult,这是一个简单而方便的方法。如果你不想把它存储在票上,你应该用用户名查询DB来知道这个角色。无论如何,SouthNoTiTICE票是加密的和足够安全的。干杯,我可能会考虑它,尽管当我改变它时它可能会表现出奇怪的行为。用户在系统上的角色。我仍在研究为什么我在操作方法中访问的
用户
与我在
global.asax
中设置的角色不同。这是一个很好的观点。我通常在会话过期时刷新FormsAuthenticationTicket以限制这种可能性。无论如何,查看您的代码可能是您的问题是由于调用user.IsInRole提前。请尝试在HttpContext.Response.Cookies.Add(cookie)之后设置HttpContext.Current.user;干杯,我已将票据更改为使用持久Cookies,奇怪的是,当我调试
用户
对象(一个
IPrincipal
)我看不到对象图中的任何角色。今晚我将看一看您的示例。我读到,创建自己的成员资格提供程序非常重要,有点过时,我可以通过基于表单的身份验证实现同样的效果。我看了一些GitHub项目,人们曾尝试过类似RavenDB成员资格提供程序,它们似乎有点不完整。成员资格提供程序模型存在一些问题,但使用它的好处是ASP.NET可以为您处理大部分安全框架。您不需要完整的成员资格和角色提供程序,就可以使其在ASP.NET中正常工作。许多方法都不是必需的,而且没有看到关于最小值的详细描述。提供商模型的一个抱怨。如果不使用它,您仍然可以利用ClaimsPrincipal来存储您的角色,而不是cookie。我认为如果您这样做,您仍然可以重用默认的authorized属性。干杯,我现在有一些想法要解决,所以我“ll+1两个答案都是。我使用的当前模型非常适合身份验证,只是不适合角色,所以我离此不远。如果我可以使用此
ClaimsPrincipal
可能就是答案。我认为membershipprovider不值得。主要是因为,如我所说,将其与其他数据访问集成或向用户类添加自定义属性是一件痛苦的事主要问题是您使用的是GenericEntity而不是FormSidenty使用
GenericEntity
会很好。我使用
FormSidenty
的唯一原因是它有一个更能揭示意图的构造函数。解决方案是主对象基于声明,并使用正确的对象来创建正如MVC 4所声称的那样,dd角色是可以被识别的。您有什么理由不能用FormsAuthentication.SetAuthCookie(model.Email,createPersistentCookie:true)替换大部分帐户/登录代码(从分配票据开始)吗?谢谢@RhysC我已经更新了答案。
FormsAuthentication.SetAuthCookie()
似乎是一种更好的方式来执行我以前手工操作的所有操作。
FormsAuthentication.SetAuthCookie(username, false);
public ActionResult Login()
{
    LoginViewModel model = new LoginViewModel();

    if ((HttpContext.User != null) &&
        (HttpContext.User.Identity.IsAuthenticated))
    {
        return RedirectToAction("Index", "Home");
    }

    return View(model);
}

[HttpPost]
public ActionResult Login(LoginViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    bool isAuthenticated = this.userService.IsPasswordValid(model.Email, model.Password);

    if (!isAuthenticated)
    {
        ModelState.AddModelError("AuthError", Resources.User.Login.AuthError);

        return View(model);
    }

    FormsAuthentication.SetAuthCookie(model.Email, model.RememberUser);

    return RedirectToAction("Index", "Home");
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

    if (authCookie != null)
    {
        var ticket = FormsAuthentication.Decrypt(authCookie.Value);

        FormsIdentity formsIdentity = new FormsIdentity(ticket);

        ClaimsIdentity claimsIdentity = new ClaimsIdentity(formsIdentity);

        var user = this.UserService.GetUserByEmail(ticket.Name);

        foreach (var role in user.Roles)
        {
            claimsIdentity.AddClaim(
                new Claim(ClaimTypes.Role, role));
        }

        ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

        HttpContext.Current.User = claimsPrincipal;
    }
}