MVC 5 OWIN 使用声明和 AntiforgeryToken 登录。我是否错过了 ClaimsIdentity 提供商?

问题描述 投票:0回答:7

我正在尝试学习 MVC 5 OWIN 登录的声明。我尝试让它尽可能简单。我从 MVC 模板开始并插入我的声明代码(见下文)。当我在视图中使用 @Html.AntiForgeryToken() 帮助程序时,出现错误。

错误:

A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' or  
'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovid    
er' was not present on the provided ClaimsIdentity. 

To enable anti-forgery token support with claims-based authentication, please verify that 
the configured claims provider is providing both of these claims on the ClaimsIdentity 
instances it generates. If the configured claims provider instead uses a different claim 
type as a unique identifier, it can be configured by setting the static property 
AntiForgeryConfig.UniqueClaimTypeIdentifier.

Exception Details: System.InvalidOperationException: A claim of type
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' or 
'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider' was 
not present on the provided ClaimsIdentity. To enable anti-forgery token
support with claims-based authentication, please verify that the configured claims provider 
is providing both of these claims on the ClaimsIdentity instances it generates. 
If the configured claims provider instead uses a different claim type as a unique 
identifier, it can be configured by setting the static property 
AntiForgeryConfig.UniqueClaimTypeIdentifier.

Source Error:
Line 4:      using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new 
{ id = "logoutForm", @class = "navbar-right" }))
Line 5:      {
Line 6:      @Html.AntiForgeryToken()

POST 登录操作

// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, "Brock"),
        new Claim(ClaimTypes.Email, "[email protected]")
    };
    var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

    var ctx = Request.GetOwinContext();
    var authenticationManager = ctx.Authentication;
    authenticationManager.SignIn(id);

    return RedirectToAction("Welcome");
}

_LoginPartial.cshtml

@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated)
{
    using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
    {
    @Html.AntiForgeryToken()

    <ul class="nav navbar-nav navbar-right">
        <li>
            @Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
        </li>
        <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
    </ul>
    }
}

我尝试过设置

ClaimTypes.NameIdentifier
就像这个SO答案

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
}

然后我“只是?”出现此错误

A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' was 
not present on the provided ClaimsIdentity.

我想保留 antiforgeryToken,因为它可以帮助防止跨站脚本。

asp.net-mvc asp.net-mvc-4 razor asp.net-mvc-5 claims-based-identity
7个回答
18
投票

在您的

Application_Start()
中,指定要使用哪个
Claim
作为
NameIdentifier
:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier = 
            System.Security.Claims.ClaimTypes.NameIdentifier;

        ...
    }
}

参见:http://brockallen.com/2012/07/08/mvc-4-antiforgerytoken-and-claims/


16
投票

您的声明身份没有

ClaimTypes.NameIdentifier
,您应该在声明数组中添加更多内容:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, "username"),
    new Claim(ClaimTypes.Email, "[email protected]"),
    new Claim(ClaimTypes.NameIdentifier, "userId"), //should be userid
};

要将信息映射到索赔以进行更多纠正:

ClaimTypes.Name => map to username
ClaimTypes.NameIdentifier => map to user_id

由于用户名也是唯一的,因此您可以使用

username
来支持防伪令牌。


5
投票

防伪配置

解决此问题的一种方法是将 AntiForgeryConfig 设置为使用其他 ClaimType。

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
}

添加 NameIdentifier 和 IdentityProvider ClaimTypes

或者,您可以将 NameIdentifier 和 IdentityProvider ClaimTypes 添加到您的声明中。

List<Claim> _claims = new List<Claim>();
_claims.AddRange(new List<Claim>
{
    new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", _user.Email)),
    new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", _user.Email)
})

参见:https://stack247.wordpress.com/2013/02/22/antiforgerytoken-a-claim-of-type-nameidentifier-or-identityprovider-was-not-present-on-provided-claimsidentity/


3
投票

我在 Global.asax.cs Application_Start() 上使用了这个并解决了错误:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;


2
投票

您的 Global.asax.cs 文件应如下所示:

namespace YOUR_PROJECT_NAME
{
    public class MvcApplication : System.Web.HttpApplication
    {
         protected void Application_Start()
         {
             AreaRegistration.RegisterAllAreas();
             RouteConfig.RegisterRoutes(RouteTable.Routes);
             AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
         }
    }
}

意味着如果它不像thta,你必须添加以下代码:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

并且不要忘记将“YOUR_PROJECT_NAME”更改为您的。


1
投票

我遇到了与此类似的问题,结果与 cookie 相关;我正在同时开发两个 MVC 站点,并且由于 ASP.Net 站点默认情况下都使用相同的 cookie 名称,因此这两个站点会互相干扰。清除cookie解决了这个问题。我的答案中有更多相关内容。


0
投票

在 Global.cs 中使用以下

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;

或者您也可以在 Global.cs 中设置您的声明类型,如下所示

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

然后根据索赔类型将索赔添加到索赔列表中。以下是声明类型“name”和“nameidentifier”的示例。使用 Session.SessionId 作为名称或 nameidentifier。

 claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", Session.SessionID));
 claims.Add(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Session.SessionID));
© www.soinside.com 2019 - 2024. All rights reserved.