- 파일업로드 체크
- 맥 오라클설치
- javascript redirection
- SSD 복사
- javascript 바코드 생성
- javascript 유효성체크
- 파일업로드 유효성체크
- asp.net Select
- 말줄임표시
- 404에러페이지
- 강제이동
- django 엑셀불러오기
- asp.net dropdownlist
- XSS방어
- Mac Oracle
- ViewBag
- javascript 바코드스캔
- 바코드 생성하기
- 바코드 스캔하기
- 하드 윈도우 복사
- 타임피커
- jquery 바코드
- XSS PHP
- php 캐쉬제거
- TempData
- jquery 바코드생성
- asp.net core Select
- ASP.Net Core 404
- 하드 마이그레이션
- ViewData
웹개발자의 기지개
[ASP.Net Core] Identity Entity FrameworkCore - 회원가입/로그인/로그아웃 예제 본문
[ASP.Net Core] Identity Entity FrameworkCore - 회원가입/로그인/로그아웃 예제
http://portfolio.wonpaper.net 2023. 2. 28. 03:41ASP.Net Core 상에서 회원가입/로그인/로그아웃 라이브러리를 EF Core 형태로 별도로 제공한다.
이러한 Identity 를 간단한 예제와 함께 확인해 보았다.
[전체 예제 소스]
https://github.com/wonpaper/IdentityMVC_Login1
SecurityController.cs 와 Security 폴더내에 DbContext파일과 User, Role 관련 클래스 파일과 Views/Security 폴더네에 로그인/회원가입 파일(Register.cshtml, SignIn.cshtml)들로 구성되어 있다.
[ appsettings.json ] - DB 연결
1
2
3
4
5
6
7
8
9
10
11
12
13
|
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"AppDb": "Server=DESKTOP-ASIDMUS;Database=IdentityMVCDB;Trusted_Connection=True;MultipleActiveResultSets=true",
"ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Database=IdentityMVCDB;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
|
cs |
EF 관련 Nuget패키지 또한 적절히 설치하였다.
[ Security/AppIdentityDbContext.cs ]
1
2
3
4
5
6
7
8
9
10
11
12
13
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace IdentityMVCExam.Security
{
public class AppIdentityDbContext : IdentityDbContext<AppIdentityUser,AppIdentityRole,string>
{
public AppIdentityDbContext(DbContextOptions<AppIdentityDbContext> options) : base(options)
{
}
}
}
|
cs |
IdentityDbContext<TUser,TRole,TKey> 에 맞게 배치되도록 Identity 관련 IdentityDbContext 클래스를 상속받는다.
[ /Security/AppIdentityUser.cs ] - Custom 할 IdentityUser 항목들 ( FullName, BirthDate )
1
2
3
4
5
6
7
8
9
10
|
using Microsoft.AspNetCore.Identity;
namespace IdentityMVCExam.Security
{
public class AppIdentityUser : IdentityUser
{
public string FullName { get;set; } = string.Empty;
public DateTime BirthDate { get; set; }
}
}
|
cs |
[ /Security/AppIdentityRole.cs ] - Custom 할 IdentityRole 항목들 ( Description )
1
2
3
4
5
6
7
8
9
10
|
using Microsoft.AspNetCore.Identity;
namespace IdentityMVCExam.Security
{
public class AppIdentityRole : IdentityRole
{
public string Description { get; set; } = string.Empty;
}
}
|
cs |
[ DB Migration ]
패키지관리자 콘솔을 열고,
PM> Add-Migration IdentityMVC -Context AppIdentityDbContext
PM> Update-Database -Context AppIdentityDbContext
MS 에서 Identity 세부 속성과 설정 부분 참고하면 된다.
비밀번호 규칙도 변경 가능하다.
[ Program.cs ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
using IdentityMVCExam.Security;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("AppDb") ?? throw new InvalidOperationException("Connection string 'ApplicationDbContextConnection' not found.");
// DbContext 연결, Identity 등록, EF에 DbContext 등록
builder.Services.AddDbContext<AppIdentityDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddIdentity<AppIdentityUser,AppIdentityRole>().AddEntityFrameworkStores<AppIdentityDbContext>();
builder.Services.ConfigureApplicationCookie(opt => {
opt.LoginPath = "/Security/SignIn"; // 로그인 처리페이지
opt.AccessDeniedPath = "/Security/AccessDenied"; // 접근권한 없는 User가 접근할때 처리페이지
});
builder.Services.Configure<IdentityOptions>(options =>
{
// 비밀번호 규칙
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 8;
options.Password.RequiredUniqueChars = 0;
});
// Add services to the container.
builder.Services.AddControllersWithViews();
#region [1] Session 개체 사용
//[0] 세션 개체 사용: Microsoft.AspNetCore.Session.dll NuGet 패키지 참조
//services.AddSession();
// Session 개체 사용시 옵션 부여
builder.Services.AddSession(options =>
{
// 세션 유지 시간
options.IdleTimeout = TimeSpan.FromMinutes(30);
});
#endregion
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
|
cs |
[ /Views/_ViewImports.cshtml ] - Identity 관련 항목들 using 시킨다.
1
2
3
4
5
6
|
@using IdentityMVCExam
@using IdentityMVCExam.Models
@using Microsoft.AspNetCore.Identity
@using Microsoft.AspNetCore.Authorization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
cs |
[ /Controllers/SecurityController.cs ] - Controller 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
using IdentityMVCExam.Models;
using IdentityMVCExam.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace IdentityMVCExam.Controllers
{
public class SecurityController : Controller
{
private readonly UserManager<AppIdentityUser> userManager;
private readonly RoleManager<AppIdentityRole> roleManager;
private readonly SignInManager<AppIdentityUser> signinManager;
public SecurityController(UserManager<AppIdentityUser> userManager, RoleManager<AppIdentityRole> roleManager,
SignInManager<AppIdentityUser> signinManager)
{
this.userManager = userManager;
this.roleManager = roleManager;
this.signinManager = signinManager;
}
// 회원가입
public IActionResult Register()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Register(Register obj)
{
if (ModelState.IsValid)
{
// 최초 회원가입시 Manager Role이 없으면 Manager Role 값을 생성해준다.
if (!roleManager.RoleExistsAsync("Manager").Result)
{
AppIdentityRole role = new AppIdentityRole();
role.Name = "Manager";
role.Description = "Can perform CRUD operations.";
IdentityResult roleResult = roleManager.CreateAsync(role).Result;
}
AppIdentityUser user = new AppIdentityUser();
user.UserName = obj.UserName;
user.Email = obj.Email;
user.FullName = obj.FullName;
user.BirthDate = obj.BirthDate;
// AppIdentityUser 생성한다.
IdentityResult result = userManager.CreateAsync(user, obj.Password).Result;
if (result.Succeeded)
{
// User 에 Manager Role을 추가해준다. 이때 Wait() 는 비동기처리로 진행이 완료될때까지 잠시 기다려준다.
userManager.AddToRoleAsync(user, "Manager").Wait();
return RedirectToAction("SignIn", "Security");
}
else
{
ModelState.AddModelError("", "회원가입 입력 항목을 모두 정확하게 입력해 주십시오.");
}
}
return View(obj);
}
// 로그인
public IActionResult SignIn()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult SignIn(SignIn obj)
{
if (ModelState.IsValid)
{
var result = signinManager.PasswordSignInAsync(obj.UserName, obj.Password,obj.RememberMe, false).Result;
if (result.Succeeded)
{
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", "로그인 사용자 정보가 맞지 않습니다.");
}
}
return View(obj);
}
// 로그아웃
// 로그아웃
[HttpGet]
public IActionResult SignOut()
{
signinManager.SignOutAsync().Wait();
return RedirectToAction("Index", "Home");
}
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public IActionResult SignOutPost()
{
signinManager.SignOutAsync().Wait();
return RedirectToAction("Index", "Home");
}
// 접근허용금지 처리
public IActionResult AccessDenied()
{
return View();
}
}
}
|
cs |
[ /Models/Register.cs ] - Model 관련 회원가입시 폼틀이 되는 클래스 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;
namespace IdentityMVCExam.Models
{
public class Register
{
[Required(ErrorMessage = "{0}을 입력해 주십시오.")]
[Display(Name = "사용자이름")]
public string UserName { get; set; }
[Required(ErrorMessage = "{0}를 입력해 주십시오.")]
[Display(Name = "비밀번호")]
public string Password { get; set; }
[Required(ErrorMessage = "{0}란을 입력해 주십시오.")]
[Display(Name = "비밀번호 확인")]
[Compare("Password", ErrorMessage = "입력하신 비밀번호와 일치하지 않습니다.")]
public string ConfirmPassword { get; set; }
[Required(ErrorMessage = "{0}을 입력해 주십시오.")]
[Display(Name = "이메일")]
[EmailAddress]
public string Email { get; set; }
[Required(ErrorMessage = "{0}을 입력해 주십시오.")]
[Display(Name = "사용자이름(전체)")]
public string FullName { get; set; }
[Required(ErrorMessage = "{0}을 제대로 선택해 주십시오.")]
[Display(Name = "생년월일")]
public DateTime BirthDate { get; set; }
}
}
|
cs |
[ /Models/SignIn.cs ] - Model 관련 로그인 폼틀이 되는 클래스 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;
namespace IdentityMVCExam.Models
{
public class SignIn
{
[Required(ErrorMessage="{0}을 입력해 주십시오.")]
[Display(Name = "사용자이름")]
public string UserName { get; set; }
[Required(ErrorMessage = "{0}를 입력해 주십시오.")]
[Display(Name = "비밀번호")]
public string Password { get; set; }
[Required]
[Display(Name = "사용자저장")]
public bool RememberMe { get; set; }
}
}
|
cs |
[ /Views/Security/Register.cshtml ] - View 관련 회원가입 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
@model Register
<h2>회원가입</h2>
<form asp-controller="Security" asp-action="Register" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<table>
<tr>
<td class="right"><label asp-for="UserName">이름</label> :</td>
<td class="left"><input type="text" asp-for="UserName" /></td>
</tr>
<tr>
<td class="right"><label asp-for="Password">비밀번호</label> :</td>
<td class="left"><input type="password" asp-for="Password" /></td>
</tr>
<tr>
<td class="right"><label asp-for="ConfirmPassword">비밀번호 확인</label> :</td>
<td class="left"><input type="password" asp-for="ConfirmPassword" /></td>
</tr>
<tr>
<td class="right"><label asp-for="Email">이메일</label> :</td>
<td class="left"><input type="text" asp-for="Email" /></td>
</tr>
<tr>
<td class="right"><label asp-for="FullName">전체 이름</label> :</td>
<td><input type="text" asp-for="FullName" /></td>
</tr>
<tr>
<td class="right"><label asp-for="BirthDate">생년월일</label> :</td>
<td class="left"><input type="date" asp-for="BirthDate" /></td>
</tr>
<tr>
<td colspan="2">
<button type="submit">회원가입하기</button>
</td>
</tr>
</table>
<a asp-controller="Security" asp-action="SignIn">[로그인페이지로 이동하기]</a>
</form>
|
cs |
[ /Views/Security/SignIn.cshtml ] - View 관련 로그인 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@model SignIn
<h2>로그인</h2>
<form asp-controller="Security" asp-action="SignIn" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<table>
<tr>
<td class="right"><label asp-for="UserName">이름</label> :</td>
<td class="left"><input type="text" asp-for="UserName" /></td>
</tr>
<tr>
<td class="right"><label asp-for="Password">비밀번호</label> :</td>
<td class="left"><input type="password" asp-for="Password" /></td>
</tr>
<tr>
<td class="right"><label asp-for="RememberMe">사용자저장</label> :</td>
<td class="left"><input type="checkbox" asp-for="RememberMe" /></td>
</tr>
<tr>
<td colspan="2">
<button type="submit">로그인</button>
</td>
</tr>
</table>
<a asp-controller="security" asp-action="register">[회원가입]</a>
</form>
|
cs |
[ /Views/_Layout.cshtml ] - 레이아웃 관련 틀 cs페이지 (회원로그인과 비로그인 상태 확인)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - IdentityMVCExam</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/IdentityMVCExam.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">IdentityMVC예제</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
@if (User.Identity.IsAuthenticated) {
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Security" asp-action="SignOut">@User.Identity.Name 님 로그아웃</a>
</li>
} else {
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Security" asp-action="SignIn">로그인</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Security" asp-action="Register">회원가입</a>
</li>
}
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<br /><br />
<hr />
@if (User.Identity.IsAuthenticated) {
<h2>@User.Identity.Name 님 로그인하였습니다.</h2>
<form asp-controller="Security" asp-action="SignOutPost" method="post">
<button type="submit">로그아웃</button>
</form>
}
<footer class="border-top footer text-muted">
<div class="container">
© 2023 - IdentityMVC예제
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
|
cs |
User.Identity.IsAuthenticated 으로 로그인인지 구분하고,
User.Identity.Name 값을 불러올 수 있다.
이제 전체 빌드하고 돌려보고 DB 의 데이터 삽입된 내용을 살펴보면,
회원가입시 Custom 한 FullName, BirthDate 항목과 데이터 내용을 살펴본다.
Role 은 Description 이라는 역할을 최초 회원가입시에 자동 Insert 되도록 해놓았다.
참고 : https://github.com/Apress/beg-database-prog-using-asp.net-core-3
[ Apress Beginning DataBase Programming Using ASP.Net Core 3 에서 Identity 부분 참고]