Необработанное исключение System.InvalidOperationException нарушает работу моего приложения MVC?

Я использую концепцию создания входа в OWIN из пустой MVC, и я только начинаю добавлять часть с использованием моей базы данных для входа в систему пользователя после создания заявки на идентификацию для ввода URL-адреса.

Это мой код для создания заявки на вход пользователя

public class AuthenticationController : Controller
{
    IAuthenticationManager Authentication
    {
        get { return HttpContext.GetOwinContext().Authentication; }
    }

    [GET("Login")]
    public ActionResult Show()
    {
        return View();
    }

    [POST("Login")]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginModel input)
    {
        if (ModelState.IsValid)
        {
            if (input.HasValidUsernameAndPassword())
            {
                var identity = new ClaimsIdentity(new[] 
                {
                        new Claim(ClaimTypes.Name, input.Username),
                },
                DefaultAuthenticationTypes.ApplicationCookie,
                ClaimTypes.Name, ClaimTypes.Role);

                // if you want roles, just add as many as you want here (for loop maybe?)
                if (input.isAdministrator)
                {
                    identity.AddClaim(new Claim(ClaimTypes.Role, "Admins"));
                }
                else
                {
                    identity.AddClaim(new Claim(ClaimTypes.Role, "User"));
                }
                // tell OWIN the identity provider, optional
                // identity.AddClaim(new Claim(IdentityProvider, "Simplest Auth"));

                Authentication.SignIn(new AuthenticationProperties
                {
                    IsPersistent = input.RememberMe
                }, identity);

                return RedirectToAction("show", "authentication");
            }
        }
        return View("show", input);
    }

    [GET("logout")]
    public ActionResult Logout()
    {
        Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
        return RedirectToAction("Login");
    }
}

Вот мой код для Show.cshtml

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>Details</h4>
    <hr />
    @Html.ValidationSummary(true)

    <div class="form-group">
        @Html.LabelFor(model => model.Username, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Username)
            @Html.ValidationMessageFor(model => model.Username)
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Password, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Password)
            @Html.ValidationMessageFor(model => model.Password)
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.RememberMe, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.RememberMe)
            @Html.ValidationMessageFor(model => model.RememberMe)
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Login" class="btn btn-default" />
        </div>
    </div>
</div>
}

Это мой код, в котором я вызываю свою базу данных и сохраняю данные для вошедшего в систему пользователя.

public class LoginModel
{
    [Required]
    public string Username { get; set; }
    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    public bool RememberMe { get; set; }

    public bool isAdministrator { get; set; }

    public bool HasValidUsernameAndPassword()
    {
        bool result = false;
        int countChecker = 0;
        using (SqlConnection connection = new SqlConnection("server=server; database=db; user id=user; password=user"))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand("SELECT count(*) FROM ACCOUNTS WHERE active = 1 AND UserName = @param1 AND PasswordField = @param2", connection))
            {
                command.Parameters.Clear();
                command.Parameters.AddWithValue("@param1", Username);
                command.Parameters.AddWithValue("@param2", Password);
                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        countChecker = Convert.ToInt32(reader[i].ToString());

                    }
                }
                if (countChecker > 0)
                {
                    result = true;
                    using (SqlConnection connect = new SqlConnection("server=server; database=db; user id=user; password=user"))
                    {
                        connect.Open();
                        using (SqlCommand com = new SqlCommand("SELECT Administrator FROM ACCOUNTS WHERE active = 1 AND UserName = @param1 AND PasswordField = @param2", connect))
                        {
                            com.Parameters.Clear();
                            com.Parameters.AddWithValue("@param1", Username);
                            com.Parameters.AddWithValue("@param2", Password);
                            SqlDataReader read = com.ExecuteReader();
                            while (read.Read())
                            {
                                for (int i = 0; i < read.FieldCount; i++)
                                {
                                    isAdministrator = Convert.ToBoolean(read[i].ToString());
                                }
                            }
                        }
                        connect.Dispose();
                        connect.Close();
                    }
                }
                else
                {
                    result = false;
                }
            }
            connection.Dispose();
            connection.Close();
        }
        return result;
    }
}

Мой логин (вход LoginModel) завершается и возвращается в Show.cshtml, а затем возникает исключение прямо здесь @ Html.AntiForgeryToken (). Исключение, которое я получаю:

Заявление типа 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier 'или' http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider 'отсутствовал в предоставленном ClaimsIdentity. Чтобы включить поддержку токенов защиты от подделки с проверкой подлинности на основе утверждений, убедитесь, что настроенный поставщик утверждений предоставляет оба этих утверждения для создаваемых им экземпляров ClaimsIdentity. Если настроенный поставщик утверждений вместо этого использует другой тип утверждения в качестве уникального идентификатора, его можно настроить, задав статическое свойство AntiForgeryConfig.UniqueClaimTypeIdentifier.

Я новичок в работе с MVC, и я не могу сказать, какой из них отсутствует в ActionResult Login (вход LoginModel). Может кто-нибудь объяснить мне, какой из них мне не хватает.

Я добавил предложение Кори в свой Global.asax:

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

Теперь я понял:

Дополнительная информация: утверждение типа 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier "отсутствовал в предоставленном ClaimsIdentity.

Я изменил AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier; в AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name; и у меня больше нет исключений. Будет ли это правильный синтаксис?


person DotNet Programmer    schedule 10.06.2015    source источник


Ответы (1)


Эта статья может помочь:

К сожалению, эта ошибка немного сбивает с толку, потому что в ней написано «nameidentifier или identityprovider», даже если у вас может быть один из двух. По умолчанию вам нужны оба.

В любом случае, если вы не используете ACS в качестве STS, указанная выше ошибка в значительной степени подскажет, что необходимо для решения проблемы. Вам нужно указать MVC, какое утверждение вы хотите использовать для уникальной идентификации пользователя. Для этого нужно установить свойство AntiForgeryConfig.UniqueClaimTypeIdentifier (обычно в App_Start в global.asax). Например (при условии, что вы хотите использовать nameidentifier в качестве уникального утверждения):

protected void Application_Start()
{
    ...

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
}
person Cory Charlton    schedule 10.06.2015
comment
Дополнительная информация: утверждение типа 'schemas.xmlsoap.org/ws/ 2005/05 / identity / Claims / nameidentifier "не присутствовал в предоставленном ClaimsIdentity. Я получаю это после добавления этой строки в свой код. - person DotNet Programmer; 10.06.2015
comment
И просто чтобы убедиться, что вы делаете это через if (ModelState.IsValid) и if (input.HasValidUsernameAndPassword()) во время отладки? - person Cory Charlton; 10.06.2015
comment
Да, я. Я только что обновил верхнюю часть, добавив изменения, которые я сделал, основываясь на том, что вы дали в качестве ответа. - person DotNet Programmer; 10.06.2015