2013-10-10 2 views
4

데이터베이스의 ADO.NET 모델을 만들었습니다. CRUD (엔티티 프레임 워크와 내가 만든 ADO.NET 엔티티 모델 사용)를 사용하여 새 컨트롤러를 만들었습니다.컨트롤러에서 모델 유효성 검사를 바이 패싱합니까?

내 데이터베이스에는 간단한 사용자 테이블이 있습니다. 테이블의 암호 행은 SimpleCrypto (PBKDF2)로 암호화 된 사용자 암호를 보유합니다. 유효성 검사 브라우저에서 jQuery를 함께 작동

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

: 나는 검증 다음 추가 한 내 ADO.NET의 Users.cs 모델에서

. 하지만 내 컨트롤러에서 암호를 암호화하고 암호 문자열이 길이가 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 길이 문자로 변경하기 때문에 오류가 발생하는 유효성 검사입니다.

편집 :이 질문에 전체 컨트롤러 섹션이 삽입되었습니다.

[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

만약 내가 제대로 이해하고 암호 필드와 데이터베이스 테이블이있다. 이 암호 필드 모델에 따르면

[StringLength(20, MinimumLength = 6)] 

20 자입니다 그리고 당신은 20 자 다음 큰 값을 삽입 할.
엔티티 프레임 워크가 사용자를 멈추게하지 않으면 데이터베이스 오류가 발생합니다 (엔티티 프레임 워크는 데이터 모델과 데이터베이스 사이의 불일치를 알지 못하므로 삽입을 밀어 내지 않을 위험이 있습니다)

그러나 데이터베이스의 길이 제한이 아니라 viewmodel에 clientSide 유효성 검사 규칙을 지정한다고 가정합니다.
이것이 왜 혼란스러운 설정인지 확인하시기 바랍니다. 당신의 ViewModel 분할 및 모델까지 그래서 당신은 당신이 너무 많은 것을 발견하면 길이가 100

와 모델 암호로 변환 할 수있는 최대 길이 (20)의 암호화되지 않은 암호로 뷰 모델을 게시 할 수 있습니다에 내 조언이 될 것

hathle을 사용하면 매핑되지 않은 비밀번호 속성을 만들 수 있습니다.이 속성은 게시 할 때 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

네, 저를 올바르게 이해합니다. 그러나 암호 필드의 실제 최대 길이는 300입니다. ViewModels에 대해 읽어야합니다. 감사합니다 – user1281991

+0

당신은 뷰 모델을 필요로하지 않습니다. stringLength 속성은 엔티티 프레임 워크 유효성 검사와 클라이언트 측 유효성 검사를 모두 트리거합니다. 따라서 StringLength 20을 사용하면 변경 사항을 제출할 때 엔티티 프레임 워크 검사와 클라이언트 측 평가 트리거가 수행됩니다. 매핑되지 않은 속성 (EF에서는 사용하지 않음)을 사용하면 PlainTextPassword에서 clientSide 유효성 검사를 트리거 할 수 있지만 Password에는 엔터티 프레임 워크 바인딩을 유지할 수 있습니다. 원하는 경우 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'DB 테이블 열보다 길게 암호화하는 것이 합리적입니다. 이 프로젝트 코드가 먼저 또는 데이터베이스가 먼저 있습니까? –

+0

DB에서 문제가되는 길이가 될 수 없습니다. DB의 암호 길이는 300으로 설정됩니다. Visual Studio에서 디버깅을 시도했는데 입력 한 임의의 암호가 다음과 같이 암호화되었습니다. "HS90iFjoivSHcc1D6Ynt6liYKr + VKpcOu1nPwUhe5qPqGbjRUfEzff93VdsicETbFOnNmyaxyc6VrVimiQGNww =="나는 100 자 같습니까? 내 모델에서 암호 유효성 검사를 제거하면 작동합니까? 오류가 발생하지 않고 모든 것이 DB에 저장됩니다. – user1281991

8

여기가 ViewModels이 게임을 시작하는 곳입니다. 나중에 뷰에 전달한 모델을 만들어 도메인 모델에 다시 매핑해야합니다.

뷰 모델 :

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 모델) :

GET 조치 :

public class User 
{ 
    // other properties.. 

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

당신은이 같은 컨트롤러에이 모델을 사용할 수 있습니다 :

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을보기에, "User"모델을 컨트롤러에만 "바인딩"하는 방법은 무엇입니까? – user1281991

+1

이 질문을 납치해서 죄송합니다.하지만보기와 컨트롤러에 서로 다른 두 가지 모델을 구속해서는 안됩니다. 뷰에'RegisterModel'을 전달하면'RegisterModel'이 돌아올 것으로 예상됩니다. MVC는 바로이 이유 때문에 자체 바인딩 핸들러를 가지고 있습니다. 나는 당신이 더 읽기를 제안한다 : http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-3 –

+0

@ user1281991 나는 두 명의 컨트롤러의 예를 가지고 나의 anwer를 업데이트했다. 행동과 견해. –

관련 문제