■ Identity 인증를 사용해 IdentityUser 객체에 커스텀 관리 항목을 추가하는 방법을 보여준다.
▶ appsettings.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
{ "MailAddress" : { "Server" : "smtp.live.com", "Port" : 587, "SenderName" : "sender", "SenderEmail" : "sender@hotmail.com", "Account" : "sender@hotmail.com", "Password" : "password", "Security" : true }, "Logging" : { "LogLevel" : { "Default" : "Information", "Microsoft" : "Warning", "Microsoft.Hosting.Lifetime" : "Information" } }, "AllowedHosts" : "*" } |
▶ Data/DatabaseContext.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 |
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using TestProject.Models; namespace TestProject.Data { /// <summary> /// 데이터베이스 컨텍스트 /// </summary> public class DatabaseContext : IdentityDbContext<ApplicationUser> { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - DatabaseContext(options) /// <summary> /// 생성자 /// </summary> /// <param name="options">옵션</param> public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { } #endregion } } |
▶ Models/ApplicationUser.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 |
using Microsoft.AspNetCore.Identity; namespace TestProject.Models { /// <summary> /// 애플리케이션 사용자 /// </summary> public class ApplicationUser : IdentityUser { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 부서 - Department /// <summary> /// 부서 /// </summary> public string Department { get; set; } #endregion } } |
▶ Startup.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 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 121 122 123 124 125 126 127 128 129 130 131 |
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using NETCore.MailKit.Extensions; using NETCore.MailKit.Infrastructure.Internal; using TestProject.Data; using TestProject.Models; namespace TestProject { /// <summary> /// 시작 /// </summary> public class Startup { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 구성 /// </summary> private IConfiguration configuration; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Startup(configuration) /// <summary> /// 생성자 /// </summary> /// <param name="configuration">구성</param> public Startup(IConfiguration configuration) { this.configuration = configuration; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 서비스 컬렉션 구성하기 - ConfigureServices(services) /// <summary> /// 서비스 컬렉션 구성하기 /// </summary> /// <param name="services">서비스 컬렉션</param> public void ConfigureServices(IServiceCollection services) { services.AddDbContext<DatabaseContext>(options => { options.UseInMemoryDatabase("TestDB"); }); services.AddIdentity<ApplicationUser, IdentityRole> ( options => { options.Password.RequiredLength = 4; options.Password.RequireDigit = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.SignIn.RequireConfirmedEmail = true; } ) .AddEntityFrameworkStores<DatabaseContext>() .AddDefaultTokenProviders(); services.ConfigureApplicationCookie ( options => { options.Cookie.Name = "TestCookie"; options.LoginPath = "/Home/Login"; } ); services.AddMailKit ( options => { options.UseMailKit(this.configuration.GetSection("MailAddress").Get<MailKitOptions>()); } ); services.AddControllersWithViews(); } #endregion #region 구성하기 - Configure(app, environment) /// <summary> /// 구성하기 /// </summary> /// <param name="app">애플리케이션 빌더</param> /// <param name="environment">웹 호스트 환경</param> public void Configure(IApplicationBuilder app, IWebHostEnvironment environment) { if(environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints ( endpoints => { endpoints.MapDefaultControllerRoute(); } ); } #endregion } } |
▶ Controllers/HomeController.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 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using NETCore.MailKit.Core; using TestProject.Models; namespace TestProject.Controllers { /// <summary> /// 홈 컨트롤러 /// </summary> public class HomeController : Controller { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 사용자 관리자 /// </summary> private readonly UserManager<ApplicationUser> userManager; /// <summary> /// 서명 관리자 /// </summary> private readonly SignInManager<ApplicationUser> signInManager; /// <summary> /// E 메일 서비스 /// </summary> private readonly IEmailService emailService; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - HomeController(userManager, signInManager, emailService) /// <summary> /// 생성자 /// </summary> /// <param name="userManager">사용자 관리자</param> /// <param name="signInManager">서명 관리자</param> /// <param name="emailService">E 메일 서비스</param> public HomeController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IEmailService emailService) { this.userManager = userManager; this.signInManager = signInManager; this.emailService = emailService; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 인덱스 페이지 처리하기 - Index() /// <summary> /// 인덱스 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> public IActionResult Index() { return View(); } #endregion #region 비밀 페이지 처리하기 - Secret() /// <summary> /// 비밀 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> [Authorize] public IActionResult Secret() { return View(); } #endregion #region 로그인 페이지 처리하기 - Login() /// <summary> /// 로그인 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> [HttpGet] public IActionResult Login() { return View(); } #endregion #region 로그인 페이지 처리하기 - Login(userName, password) /// <summary> /// 로그인 페이지 처리하기 /// </summary> /// <param name="userName">사용자명</param> /// <param name="password">패스워드</param> /// <returns>액션 결과 태스크</returns> [HttpPost] public async Task<IActionResult> Login(string userName, string password) { ApplicationUser applicationUser = await this.userManager.FindByNameAsync(userName); if(applicationUser != null) { Microsoft.AspNetCore.Identity.SignInResult signInResult = await this.signInManager.PasswordSignInAsync ( applicationUser, password, false, false ); if(signInResult.Succeeded) { return RedirectToAction("Index"); } } return RedirectToAction("Index"); } #endregion #region 등록 페이지 처리하기 - Register() /// <summary> /// 등록 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> [HttpGet] public IActionResult Register() { return View(); } #endregion #region 등록 페이지 처리하기 - Register(userName, password, mailAddress, department) /// <summary> /// 등록 페이지 처리하기 /// </summary> /// <param name="userName">사용자명</param> /// <param name="password">패스워드</param> /// <param name="mailAddress">메일 주소</param> /// <param name="department">부서</param> /// <returns>액션 결과 태스크</returns> [HttpPost] public async Task<IActionResult> Register(string userName, string password, string mailAddress, string department) { ApplicationUser applicationUser = new ApplicationUser { UserName = userName, Email = mailAddress, Department = department }; IdentityResult result = await this.userManager.CreateAsync(applicationUser, password); if(result.Succeeded) { string code = await this.userManager.GenerateEmailConfirmationTokenAsync(applicationUser); var link = Url.Action ( "ConfirmMailAddress", "Home", new { userID = applicationUser.Id, code }, Request.Scheme, Request.Host.ToString() ); await this.emailService.SendAsync ( mailAddress, "메일 주소 확인 요청", $"<a href=\"{link}\">메일 주소 확인</a>", true ); return RedirectToAction("SendMailNotification"); } return RedirectToAction("Index"); } #endregion #region 메일 발송 통지 페이지 처리하기 - SendMailNotification() /// <summary> /// 메일 발송 통지 페이지 처리하기 /// </summary> /// <returns>액션 결과</returns> public IActionResult SendMailNotification() { return View(); } #endregion #region 메일 주소 확인 페이지 처리하기 - ConfirmMailAddress(userID, code) /// <summary> /// 메일 주소 확인 페이지 처리하기 /// </summary> /// <param name="userID">사용자 ID</param> /// <param name="code">코드</param> /// <returns>액션 결과 태스크</returns> public async Task<IActionResult> ConfirmMailAddress(string userID, string code) { ApplicationUser applicationUser = await this.userManager.FindByIdAsync(userID); if(applicationUser == null) { return BadRequest(); } IdentityResult identityResult = await this.userManager.ConfirmEmailAsync(applicationUser, code); if(identityResult.Succeeded) { return View(); } return BadRequest(); } #endregion #region 로그아웃 페이지 처리하기 - LogOut() /// <summary> /// 로그아웃 페이지 처리하기 /// </summary> /// <returns>액션 결과 태스크</returns> public async Task<IActionResult> LogOut() { await this.signInManager.SignOutAsync(); return RedirectToAction("Index"); } #endregion } } |
▶ Views/Home/Register.cshtml
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 |
<h1>등록 페이지</h1> <hr /> <form action="/Home/Register" method="post"> <table> <tr> <td>사용자명</td> <td><input type="text" name="userName" value="" /></td> </tr> <tr> <td>패스워드</td> <td><input type="password" name="password" value="" /></td> </tr> <tr> <td>메일 주소</td> <td><input type="text" name="mailAddress" value="" /></td> </tr> <tr> <td>부서</td> <td><input type="text" name="department" value="" /></td> </tr> </table> <button type="submit">등록</button> </form> |
▶ Views/Home/Login.cshtml
1 2 3 4 5 6 7 8 9 |
<h1>로그인 페이지</h1> <hr /> <form action="/Home/Login" method="post"> 사용자명 : <input type="text" name="userName" value="" /><br /> 패스워드 : <input type="text" name="password" value="" /><br /> <button type="submit">로그인</button> </form> |
※ 테스트 방법
1. appsettings.json 파일의 MailAddress 섹션에서 SenderName, SendrEmail, Account, Password 항목을 적절히 설정한다.
2. 프로그램을 실행한다.
3. 웹 브라우저에서 https://localhost:44341/home/register 페이지로 이동하고 사용자를 등록한다.
※ [사용자명], [패스워드] 및 [부서]에 테스트를 용이하기 위해서 각각 "test", "password", "sales"를 입력하고 [메일주소]는 받고자 하는 메일 주소를 입력한다.
4. 사용자 등록을 완료하면 입력한 메일을 수신하고 [메일 주소 확인] 링크를 클릭한다.
5. 웹 브라우저에서 https://localhost:44341/home/secret 페이지로 이동하면 로그인 페이지가 표시된다.
6. 로그인 페이지에서 상기 입력한 [사용자명]과 [패스워드]를 입력해 로그인한다.