2013-10-10 2 views
4

Я создал модель ADO.NET моей базы данных. Создал новый контроллер с CRUD (структура сущности и с использованием модели сущности ADO.NET, которую я создал).обход проверки модели в контроллере?

В моей базе данных У меня есть простая таблица пользователей. В строке «Пароль» в таблице будут храниться пароли пользователей, зашифрованные с помощью SimpleCrypto (PBKDF2).

В моей ADO.NET Users.cs модели я добавил следующие проверки:

[Required] 
[DataType(DataType.Password)] 
[StringLength(20, MinimumLength = 6)] 
[Display(Name = "Password")] 
public string Password { get; set; } 

Это работает с JQuery в браузере с проверкой. Но в моем контроллере я шифрую пароль, а затем строка «Пароль» будет содержать более 20 символов в длину.

var crypto = new SimpleCrypto.PBKDF2(); 
var encryptedPass = crypto.Compute(user.Password); 

user.Password = encryptedPass; 
user.PasswordSalt = crypto.Salt; 

_db.Users.Add(user); 
_db.SaveChanges(); 

И это дает мне и «Проверка не удалась для одного или нескольких объектов». - Ошибка.

Я могу скопировать пользователя в «var newUser», а затем установить все свойства там, но нет ли в этом случае более простого способа обойти проверку модели?

EDIT: Если я удалю проверку пароля в модели, тогда все будет работать. Так что это проверка, которая дает мне ошибку, потому что я изменяю пароль с 6-20 символов длины до символов +100 lengt из-за шифрования в контроллере.

РЕДАКТИРОВАТЬ: Полностью раздел контроллера включен в этот вопрос.

[HttpPost] 
public ActionResult Create(Users user) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(); 
    } 
    if (_db.Users.FirstOrDefault(u => u.Email == user.Email) != null) 
    { 
     ModelState.AddModelError("", "User already exists in database!"); 
     return View(); 
    } 

    var crypto = new SimpleCrypto.PBKDF2(); 
    var encryptedPass = crypto.Compute(user.Password); 

    user.Password = encryptedPass; 
    user.PasswordSalt = crypto.Salt; 

    _db.Users.Add(user); 
    _db.SaveChanges(); 

    return RedirectToAction("Index", "User"); 
} 
+1

Я редактировал свой титул. Пожалуйста, смотрите: «Если вопросы включают« теги »в их названиях?] (Http://meta.stackexchange.com/questions/19190/), где консенсус« нет, они не должны ». –

ответ

2

Если я правильно понимаю, у вас есть таблица базы данных с полем ввода пароля.
Согласно вашей модели это поле пароля 20 символов

[StringLength(20, MinimumLength = 6)] 

И вы хотите, чтобы вставить значение больше, чем 20 символов.
Если инфраструктура сущности не остановила вас, вы получите ошибку базы данных (инфраструктура Entity не знает, что существует несоответствие между вашей моделью данных и базой данных, и она не хочет рисковать нажатием вставки)

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

Мой совет будет либо разделить ViewModel и модель, таким образом Вы можете оставить ViewModel с незашифрованном паролем MAXLENGTH 20, который можно преобразовать в модель пароль длиной 100.

Если вы обнаружили, что слишком много вы можете создать свойство unmapped password, которое вы установили из html при его публикации, и преобразовать его в свойство пароля в своем контроллере.
Ваш класс может выглядеть следующим образом:

public class RegisterModel 
{ 
    [Required] 
    public string UserName { get; set; } 

    [Required] 
    [NotMapped] 
    [StringLength(20, MinimumLength = 6)] 
    [Display(Name = "Password")] 
    public string PlainTextPassword { get; set; } 

    [Required] 
    [StringLength(300)]//This is optional 
    [DataType(DataType.Password)] 
    public string Password { get; set; } 
} 
+0

Да, вы меня правильно поняли. Тем не менее, фактическая максимальная длина поля Password - 300. Мне кажется, мне нужно прочитать о ViewModels. Спасибо – user1281991

+0

Вам не нужна viewmodel Per se. Свойство stringLength запускает проверку как сущности, так и валидацию на стороне клиента. Поэтому, если вы скажете, что StringLength 20 запускает ваши клиентские валлиционные триггеры, а также проверку фреймворка сущности при отправке изменений. Используя свойство unmapped (которое не использует EF), вы можете инициировать проверку ClientSide на PlainTextPassword, но привяжите привязку сущности к паролю. Вы можете добавить Stringlength 300, если хотите. – Kristof

+0

СПАСИБО! Вы заставили меня понять :) Это работает! Спасибо – user1281991

3

Вы говорите, что ваше шифрование пароля происходит в контроллере. В этом случае вам не следует шифровать после проверки? Например:

public ActionResult SomeControllerAction(UserViewModel user) 
{ 
    if (!ModelState.IsValid) 
    { 
     // at this point the human readable (and assuming < 20 length) password 
     // would be getting validated 
     return View(user); 
    } 

    // now when you're writing the record to the DB, encrypt the password 
    var crypto = new SimpleCrypto.PBKDF2(); 
    var encryptedPass = crypto.Compute(user.Password); 

    user.Password = encryptedPass; 
    user.PasswordSalt = crypto.Salt; 

    _db.Users.Add(user); 
    _db.SaveChanges(); 

    // return or redirect to whatever route you need 
} 

Если вы хотите, чтобы специально контролировать свою проверку, а затем попробовать реализовать IValidatableObject на ваш взгляд модели класса и выполнить проверку здесь, вместо того, чтобы с помощью атрибутов. Например:

public class UserViewModel : IValidatableObject 
{ 
    public string Username { get; set; } 
    public string Password { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     // validate the unencrypted password's length to be < 20 
     if (this.Password.Length > 20) 
     { 
      yield return new ValidationResult("Password too long!"); 
     } 
    }   
} 
+0

Привет, спасибо. Я новичок в MVC. Я вставил в раздел контроллера в моем вопросе выше. – user1281991

+0

@ user1281991 не проблема, похоже, что ваша проверка не выполняется на уровне базы данных - вы шифруете пароль длиной более длинной, чем может быть удобно хранить столбец базы данных «User.Password». Это первый код проекта или база данных? –

+0

Не может быть длины в БД, которая дает проблему. Длина пароля в БД установлена ​​равной 300. Пробная отладка в Visual Studio и случайный пароль, который я ввел, зашифрованы следующим образом: «HS90iFjoivSHcc1D6Ynt6liYKr + VKpcOu1nPwUhe5qPqGbjRUfEzff93VdsicETbFOnNmyaxyc6VrVimiQGNww ==», который, как и 100 символов, я думаю? Если я удалю проверку пароля в моей модели, то это сработает? Ошибок не возникает, и все хорошо хранится в DB – user1281991

8

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

ViewModel:

public class RegisterModel 
{ 
    [Required] 
    public string UserName { get; set; } 

    [Required] 
    [DataType(DataType.Password)] 
    [StringLength(20, MinimumLength = 6)] 
    [Display(Name = "Password")] 
    public string Password { get; set; } 
} 

Модель предметной области (текущая User модель):

public class User 
{ 
    // other properties.. 

    [Required] 
    public string Password { get; set; } 
} 

Вы можете использовать эти модели в контроллере, как это:

The GET действия:

public ActionResult Register() 
{ 
    var registerModel = new RegisterModel(); 
    return View(registerModel) 
} 

С целью, как это:

@model RegisterModel 

@Html.LabelFor(model => model.UserName) 
@Html.TextBoxFor(model => model.UserName) 
@Html.ValidationMessageFor(model => model.UserName) 

@Html.LabelFor(model => model.Password) 
@Html.PasswordFor(model => model.Password) 
@Html.ValidationMessageFor(model => model.Password) 

И POST действие:

[HttpPost] 
public ActionResult Register(RegisterModel registerModel) 
{ 
    // Map RegisterModel to a User model.  
    var user = new User 
        { 
         UserName = registerModel.UserName, 
         Password = registerModel.Password // Do the hasing here for example. 
        }; 
    db.Users.Add(user); 
    db.SaveChanges();       
} 
+0

Спасибо за это. Тогда глупый вопрос. Как «привязать» RegisterModel к представлению и модели пользователя только к контроллеру? – user1281991

+1

Извините, что уволили этот вопрос, но вы не должны привязывать две разные модели к вашему виду и контроллеру. Вы должны передать 'RegisterModel' в свое представление, и вы ожидаете, что' RegisterModel' вернется - MVC имеет свои собственные обработчики привязки именно по этой причине. Я предлагаю вам прочитать больше: http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-3 –

+0

@ user1281991 Я обновил свой андер с примером двух контроллеров действия и вид. –

Смежные вопросы