기본적으로 HTTP 프로토콜 환경은 비연결성(Connectionless), 무상태(Stateless) 특성을 가지고 있기 때문에 서버에서 클라이언트의 사용자를 매번 확인해야 한다. 이러한 특성을 보완하기 위해 쿠키와 세션을 사용하게 되었다.
- 웹 서버 로그인 -> 사용자 정보 -> 브라우저 전달
- 쿠키는 클라이언트(브라우저) 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일
- 클라이언트 컴퓨터에 저장
- 웹 서버의 부하가 낮아지지만 보안성이 낮음
- Cookie -> 암호화 -> 복호화 / 위변조의 위험
- SSL
- 세션은 서버의 메모리가 감당할 수 없어질 수가 있고 속도가 느려질 수 있기 때문에 쿠키가 유리한 경우가 있습니다.
- 최근에는 이런 문제들을 보완한 토큰 기반의 인증방식을 사용하는 추세 ex) JWTR
namespace AspnetNote.MVC6.Models
{
public class User
{
/// <summary>
/// 사용자번호
/// </summary>
[Key] // PK 설정
public int UserNo { get; set; }
/// <summary>
/// 사용자 이름
/// </summary>
[Required(ErrorMessage ="사용자 이름을 입력하세요.")] // Not Null 설정
public string UserName { get; set; }
/// <summary>
/// 사용자 ID
/// </summary>
[Required(ErrorMessage = "사용자 아이디를 입력하세요.")] // Not Null 설정
public string UserId { get; set; }
/// <summary>
/// 사용자 비밀번호
/// </summary>
[Required(ErrorMessage = "사용자 비밀번호를 입력하세요.")] // Not Null 설정
public string UserPassword { get; set; }
}
}
<!-- asp-for가 참조할 위치를 지정해준다. -->
@model AspnetNote.MVC6.Models.User
<h2>회원가입</h2>
<!-- 폼을 Account 컨트롤러 Register 메서드로 넘겨준다. -->
<form class="form-horizontal" method="post" asp-controller="Account" asp-action="Register">
<div class="form-group">
<label> 사용자 ID</label> <!-- Models의 User의 UserId에 매칭시켜 값을 넘겨준다. -->
<input type="text" class="form-control" asp-for="UserId" placeholder="사용자 ID 입력" />
<!-- span 태그를 이용해 asp-validation-for 를 이용하면 값을 넣지 않을경우 경고문이 뜬다. -->
<span class="text-danger" asp-validation-for="UserId"></span>
</div>
<div class="form-group">
<label> 사용자 비밀번호</label>
<input type="password" class="form-control" asp-for="UserPassword" placeholder="사용자 비밀번호 입력" />
<span class="text-danger" asp-validation-for="UserPassword" ></span>
</div>
<div class="form-group">
<label> 사용자 이름</label>
<input type="text" class="form-control" asp-for="UserName" placeholder="사용자 이름 입력" />
<span class="text-danger" asp-validation-for="UserName" ></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">회원가입</button>
<a class="btn btn-warning" href="#">취소</a>
</div>
</form>
namespace AspnetNote.MVC6.Controllers
{
public class AccountController : Controller
{
/// <summary>
/// 회원가입
/// </summary>
/// <returns></returns>
public IActionResult Register()
{
return View();
}
[HttpPost]
public IActionResult Register(User model)
{ // IsValid : 모든값 입력 받았는지 검증 ID, 비밀번호 필수로 적어야 한다.
// [Required] 어노테이션을 기준으로 판단한다.
if (ModelState.IsValid)
{
/* using문을 사용하여 DB 오픈 커넥션 후 자동으로 닫게 해준다. */
using (var db = new AspnetNoteDbContext())
{
db.Users.Add(model); // 메모리상에 올라감
db.SaveChanges(); // 메모리 -> DB에 저장
}
return RedirectToAction("Index", "Home");
}
return View(model);
}
}
}
GET method는 클라이언트에서 서버로 정보를 요청하기위해 사용되는 메서드 입니다.
- 데이터 읽기(Read), 검색(Retrieve) 할때 사용되는 method
- URL 주소 끝에 파라미터로 포함되어 전송되며, 이 부분을 쿼리 스트링(QueryString) 이라고 부른다.
POST method는 리소스를 생성/업데이트 하기위해 서버에 데이터를 보내는 데 사용된다.
- 전송해야될 데이터를 HTTP Body에 담아서 전송한다.
- HTTP Body 길이의 제한이 없기 때문에 GET과 달리 대용량 데이터를 전송할 수 있다.
namespace AspnetNote.MVC6.ViewModel
{ /* View를 위한 모델 작성 */
public class LoginViewModel
{
// 로그인 할때만 사용할 View 모델
[Required(ErrorMessage ="사용자 ID를 입력해주세요")]
public string UserId{get; set;}
[Required(ErrorMessage = "사용자 비밀번호를 입력해주세요")]
public string UserPassword { get; set; }
}
}
@model AspnetNote.MVC6.ViewModel.LoginViewModel
<h2>로그인</h2>
<form class="form-horizontal" method="post" asp-controller="Account" asp-action="Login">
<!-- asp-validation-summary=”ModelOnly” : 전역적인 경고 메세지를 위해 사용한다.-->
<!-- 개별적으로 체크한 후 문제가 없으면 전역적인 체크를 하고 문제가 있으면 경고를 띄워준다. -->
<div class="text-danger" asp-validation-summary="ModelOnly"></div>
<div class="form-group">
<label>사용자 ID</label>
<input type="text" asp-for="UserId" class="form-control" placeholder="사용자 아이디 입력" />
<span class="text-danger" asp-validation-for="UserId"></span>
</div>
<div class="form-group">
<label>사용자 비밀번호</label>
<input type="password" asp-for="UserPassword" class="form-control" placeholder="비밀번호 입력" />
<span class="text-danger" asp-validation-for="UserPassword"></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">로그인</button>
</div>
</form>
public class AccountController : Controller
{
/// <summary>
/// 로그인 페이지 이동
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Login()
{
return View();
}
/* 로그인 */
[HttpPost]
public IActionResult Login(LoginViewModel model)
{
// IsValid : 모든값 입력 받았는지 검증 ID, 비밀번호 필수로 적어야 한다.
// [Required] 어노테이션을 기준으로 판단한다.
if (ModelState.IsValid)
{
// DB 오픈 커넥션 후 자동으로 닫음
using (var db = new AspnetNoteDbContext())
{
// Linq - 메서드 체이닝 (=> : A Go to B )
// 입력받은 아이디 와 Db 값 비교
// FirstOrDefault() : 첫 번째 입력값 출력하겠다. ()안에 원하는 값 넣어서 찾을 수 있다.
// 비교할때 == 를 사용하면 메모리누수가 발생하기 때문에 Equals를 사용한다.
//var user = db.Users.FirstOrDefault(u=> u.UserId == model.UserId && u.UserPassword == model.UserPassword);
var user = db.Users.FirstOrDefault(u => u.UserId.Equals(model.UserId) && u.UserPassword.Equals(model.UserPassword)); // 아이디 비밀번호 매칭
/* 로그인 성공 */
if (user != null)
{
/* HttpContext.Session.SetInt32(key, value); */
/* "USER_LOGIN_KEY"라는 이름으로 Session에 담는다. */
HttpContext.Session.SetInt32("USER_LOGIN_KEY", user.UserNo);
return RedirectToAction("LoginSuccess", "Home");
}
}
// 로그인 실패, 사용자 ID 자체가 회원가입 X 경우
ModelState.AddModelError(string.Empty, "사용자 ID 혹은 비밀번호가 올바르지 않습니다.");
}
return View(model);
}
}
}