728x90
반응형
728x170
▶ Database/TestDB.sql
CREATE TABLE dbo.[User]
(
ID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY
,UserID NVARCHAR(50) NOT NULL
,[Password] NVARCHAR(50) NOT NULL
)
GO
CREATE PROCEDURE dbo.WriteUser
@UserID NVarChar(50),
@Password NVarChar(50)
AS
INSERT INTO dbo.[User] VALUES (@UserID, @Password);
GO
CREATE PROCEDURE dbo.ListUsers
AS
SELECT
ID
,UserID
,[Password]
FROM dbo.[User]
ORDER BY ID DESC;
GO
CREATE PROCEDURE dbo.ViewUser
@ID Int
AS
SELECT
ID
,UserID
,[Password]
FROM dbo.[User]
Where ID = @ID;
GO
CREATE PROCEDURE dbo.ModifyUser
@UserID NVARCHAR(50)
,@Password NVARCHAR(50)
,@ID INT
AS
UPDATE dbo.[User]
SET
UserID = @UserID,
[Password] = @Password
WHERE ID = @ID;
GO
CREATE PROCEDURE dbo.DeleteUser
@ID INT
AS
DELETE FROM dbo.[User] WHERE ID = @ID;
GO
CREATE PROCEDURE dbo.SearchUsers
@SearchField NVarChar(50),
@SearchQuery NVarChar(50)
AS
DECLARE @SQL NVarChar(2000);
SET @SQL = 'SELECT * FROM dbo.[User] WHERE ' + @SearchField + ' LIKE ''%' + @SearchQuery + '%''';
EXECUTE @SQL;
GO
728x90
▶ appsettings.json
{
"ConnectionStrings" :
{
"DefaultConnection" : "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=TestDB;Integrated Security=True"
},
"Logging" :
{
"LogLevel" :
{
"Default" : "Information",
"Microsoft" : "Warning",
"Microsoft.Hosting.Lifetime" : "Information"
}
},
"AllowedHosts" : "*",
"MainSettings" :
{
"SiteAdministrator" : "admin"
}
}
300x250
▶ Settings/MainSettings.cs
namespace TestProject.Settings
{
/// <summary>
/// 메인 설정
/// </summary>
public class MainSettings
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 사이트 관리자 - SiteAdministrator
/// <summary>
/// 사이트 관리자
/// </summary>
public string SiteAdministrator { get; set; }
#endregion
}
}
▶ Models/UserModel.cs
using System.ComponentModel.DataAnnotations;
namespace TestProject.Models
{
/// <summary>
/// 사용자 모델
/// </summary>
public class UserModel
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region ID - ID
/// <summary>
/// ID
/// </summary>
public int ID { get; set; }
#endregion
#region 사용자 ID - UserID
/// <summary>
/// 사용자 ID
/// </summary>
[Display(Name = "사용자 ID")]
[Required(ErrorMessage = "사용자 ID를 입력해 주시기 바랍니다.")]
[StringLength(50, MinimumLength = 5, ErrorMessage = "사용자 ID는 5자 이상 50자 이하로 입력해 주시기 바랍니다.")]
public string UserID { get; set; }
#endregion
#region 패스워드 - Password
/// <summary>
/// 패스워드
/// </summary>
[Display(Name = "패스워드")]
[Required(ErrorMessage = "패스워드를 입력해 주시기 바랍니다.")]
[StringLength(50, MinimumLength = 4, ErrorMessage = "패스워드는 4자 이상 50자 이하로 입력해 주시기 바랍니다.")]
public string Password { get; set; }
#endregion
}
}
▶ Models/IUserRepository.cs
namespace TestProject.Models
{
/// <summary>
/// 사용자 저장소
/// </summary>
public interface IUserRepository
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 사용자 추가하기 - AddUser(userID, password)
/// <summary>
/// 사용자 추가하기
/// </summary>
/// <param name="userID">사용자 ID</param>
/// <param name="password">패스워드</param>
void AddUser(string userID, string password);
#endregion
#region 사용자 수정하기 - UpdateUser(id, userID, password)
/// <summary>
/// 사용자 수정하기
/// </summary>
/// <param name="id">ID</param>
/// <param name="userID">사용자 ID</param>
/// <param name="password">패스워드</param>
void UpdateUser(int id, string userID, string password);
#endregion
#region 사용자 구하기 - GetUser(userID)
/// <summary>
/// 사용자 구하기
/// </summary>
/// <param name="userID">사용자 ID</param>
/// <returns>사용자</returns>
UserModel GetUser(string userID);
#endregion
#region 사용자 검증하기 - ValidateUser(userID, password)
/// <summary>
/// 사용자 검증하기
/// </summary>
/// <param name="userID">사용자 ID</param>
/// <param name="password">패스워드</param>
/// <returns>사용자 검증 여부</returns>
bool ValidateUser(string userID, string password);
#endregion
}
}
▶ Models/UserRepository.cs
using Microsoft.Extensions.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace TestProject.Models
{
/// <summary>
/// 사용자 저장소
/// </summary>
public class UserRepository : IUserRepository
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 구성
/// </summary>
private IConfiguration configuration;
/// <summary>
/// 연결
/// </summary>
private SqlConnection connection;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - UserRepository(configuration)
/// <summary>
/// 생성자
/// </summary>
/// <param name="configuration">구성</param>
public UserRepository(IConfiguration configuration)
{
this.configuration = configuration;
string connectionString = this.configuration.GetSection("ConnectionStrings").GetSection("DefaultConnection").Value;
this.connection = new SqlConnection(connectionString);
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 사용자 추가하기 - AddUser(userID, password)
/// <summary>
/// 사용자 추가하기
/// </summary>
public void AddUser(string userID, string password)
{
SqlCommand command = new SqlCommand();
command.Connection = this.connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "WriteUser";
command.Parameters.AddWithValue("@UserID" , userID );
command.Parameters.AddWithValue("@Password", password);
try
{
this.connection.Open();
command.ExecuteNonQuery();
}
finally
{
this.connection.Close();
}
}
#endregion
#region 사용자 수정하기 - UpdateUser(id, userID, password)
/// <summary>
/// 사용자 수정하기
/// </summary>
/// <param name="id">ID</param>
/// <param name="userID">사용자 ID</param>
/// <param name="password">패스워드</param>
public void UpdateUser(int id, string userID, string password)
{
SqlCommand command = new SqlCommand();
command.Connection = this.connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "ModifyUser";
command.Parameters.AddWithValue("@UserID" , userID );
command.Parameters.AddWithValue("@Password", password);
command.Parameters.AddWithValue("@UID" , id );
try
{
this.connection.Open();
command.ExecuteNonQuery();
}
finally
{
this.connection.Close();
}
}
#endregion
#region 사용자 구하기 - GetUser(userID)
/// <summary>
/// 사용자 구하기
/// </summary>
/// <param name="userID">사용자 ID</param>
/// <returns>사용자</returns>
public UserModel GetUser(string userID)
{
SqlCommand command = new SqlCommand();
command.Connection = this.connection;
command.CommandType = CommandType.Text;
command.CommandText = "SELECT * FROM dbo.[User] WHERE UserID = @UserID";
command.Parameters.AddWithValue("@UserID", userID);
UserModel user = new UserModel();
try
{
this.connection.Open();
IDataReader reader = command.ExecuteReader();
if(reader.Read())
{
user.ID = reader.GetInt32(0);
user.UserID = reader.GetString(1);
user.Password = reader.GetString(2);
}
}
finally
{
this.connection.Close();
}
return user;
}
#endregion
#region 사용자 검증하기 - ValidateUser(userID, password)
/// <summary>
/// 사용자 검증하기
/// </summary>
/// <param name="userID">사용자 ID</param>
/// <param name="password">패스워드</param>
/// <returns>사용자 검증 여부</returns>
public bool ValidateUser(string userID, string password)
{
SqlCommand command = new SqlCommand();
command.Connection = this.connection;
command.CommandType = CommandType.Text;
command.CommandText = "SELECT * FROM dbo.[User] WHERE UserID = @UserID AND Password = @Password";
command.Parameters.AddWithValue("@UserID" , userID );
command.Parameters.AddWithValue("@Password", password);
bool result = false;
try
{
this.connection.Open();
SqlDataReader dataReader = command.ExecuteReader();
if(dataReader.Read())
{
result = true;
}
}
finally
{
this.connection.Close();
}
return result;
}
#endregion
}
}
▶ Controllers/UserController.cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using TestProject.Models;
namespace DotNetNote.Controllers
{
/// <summary>
/// 사용자 컨트롤러
/// </summary>
public class UserController : Controller
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 저장소
/// </summary>
private IUserRepository repository;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - UserController(repository)
/// <summary>
/// 생성자
/// </summary>
/// <param name="repository">저장소</param>
public UserController(IUserRepository repository)
{
this.repository = repository;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 페이지 처리하기 - Index()
/// <summary>
/// 인덱스 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
[Authorize]
public IActionResult Index()
{
return View();
}
#endregion
#region 등록 페이지 처리하기 - Register()
/// <summary>
/// 등록 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
[HttpGet]
public IActionResult Register()
{
return View();
}
#endregion
#region 등록 페이지 처리하기 - Register(user)
/// <summary>
/// 등록 페이지 처리하기
/// </summary>
/// <param name="user">사용자</param>
/// <returns>액션 결과</returns>
[HttpPost]
public IActionResult Register(UserModel user)
{
if(ModelState.IsValid)
{
if(this.repository.GetUser(user.UserID).UserID != null)
{
ModelState.AddModelError("", "등록된 사용자 입니다.");
return View(user);
}
}
if(!ModelState.IsValid)
{
ModelState.AddModelError("", "사용자 데이터에 오류가 있습니다.");
return View(user);
}
else
{
this.repository.AddUser(user.UserID, user.Password);
return RedirectToAction("Index");
}
}
#endregion
#region 로그인 페이지 처리하기 - Login(returnURL)
/// <summary>
/// 로그인 페이지 처리하기
/// </summary>
/// <param name="returnURL">반환 URL</param>
/// <returns>액션 결과</returns>
[HttpGet]
[AllowAnonymous]
public IActionResult Login(string returnURL = null)
{
ViewData["ReturnURL"] = returnURL;
return View();
}
#endregion
#region 로그인 페이지 처리하기 - Login(user, returnURL)
/// <summary>
/// 로그인 페이지 처리하기
/// </summary>
/// <param name="user">사용자</param>
/// <param name="returnURL">반환 URL</param>
/// <returns>액션 결과 태스크</returns>
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(UserModel user, string returnURL = null)
{
if(ModelState.IsValid)
{
if(this.repository.ValidateUser(user.UserID, user.Password))
{
List<Claim> claimList = new List<Claim>()
{
new Claim("UserID", user.UserID),
new Claim(ClaimTypes.Role, "Users")
};
ClaimsIdentity claimsIdentity = new ClaimsIdentity(claimList, user.Password);
await HttpContext.SignInAsync("CookieAuthentication", new ClaimsPrincipal(claimsIdentity));
return LocalRedirect("/User/Index");
}
}
return View(user);
}
#endregion
#region 로그아웃 페이치 처리하기 - Logout()
/// <summary>
/// 로그아웃 페이치 처리하기
/// </summary>
/// <returns>액션 결과 태스크</returns>
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync("CookieAuthentication");
return Redirect("/User/Index");
}
#endregion
#region 사용자 정보 페이지 처리하기 - UserInformation()
/// <summary>
/// 사용자 정보 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
[Authorize]
public IActionResult UserInformation()
{
return View();
}
#endregion
#region 인사말 페이지 처리하기 - Greetings()
/// <summary>
/// 인사말 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
public IActionResult Greetings()
{
if(User.Identity.IsAuthenticated == false)
{
return new ChallengeResult();
}
return View();
}
#endregion
#region 접근 거부 페이지 처리하기 - Forbidden()
/// <summary>
/// 접근 거부 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
public IActionResult Forbidden()
{
return View();
}
#endregion
}
}
▶ Views/Shared/_LoginPartial.cs
@using TestProject.Models
@inject Microsoft.Extensions.Options.IOptions<TestProject.Settings.MainSettings> option
@if(User.Identity.IsAuthenticated)
{
<form asp-controller="User" asp-action="Logout" method="post"
id="logoutForm" class="navbar-right">
<ul class="nav navbar-nav navbar-right">
@if(User.IsInRole("Users") && User.FindFirst("UserID").Value == option.Value.SiteAdministrator)
{
<li>
<a asp-controller="Admin" asp-action="Index"><i class="fa fa-gear"></i> 대시보드</a>
</li>
<li> </li>
}
<li>
<a asp-controller="User" asp-action="UserInformation">
@User.FindFirst("UserId").Value
</a>
</li>
<li>
<button type="submit" class="btn btn-link navbar-btn navbar-link">
로그아웃
</button>
</li>
</ul>
</form>
}
else
{
<ul class="nav navbar-nav navbar-right">
<li><a asp-controller="User" asp-action="Register">회원 가입</a></li>
<li> </li>
<li><a asp-controller="User" asp-action="Login">로그인</a></li>
</ul>
}
▶ Views/User/Index.cshtml
<h1>메인 페이지</h1>
@if(User.Identity.IsAuthenticated)
{
<span>@User.FindFirst("UserID").Value 님, 반갑습니다.</span>
<a href="/User/Logout">로그아웃</a>
}
else
{
<a href="/User/Login">로그인</a>
<a href="/User/Register">회원 가입</a>
}
▶ Views/User/Register.cshtml
@model UserModel
@{
ViewData["Title"] = "회원 가입 페이지";
}
<h2>@ViewData["Title"]</h2>
<div class="row">
<div class="col-md-8">
<section>
<form asp-controller="User" asp-action="Register" method="post" class="form-horizontal">
<h4>아래 항목을 입력해 주시기 바랍니다.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label class="col-sm-2 control-label" asp-for="UserID"></label>
<div class="col-sm-6">
<input type="text" class="form-control" asp-for="UserID" placeholder="사용자 ID">
<span asp-validation-for="UserID" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" asp-for="Password"></label>
<div class="col-sm-6">
<input type="password" class="form-control" asp-for="Password" placeholder="패스워드">
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6">
<input type="submit" value="가입" class="btn btn-primary btn-lg" />
<a asp-controller="User" asp-action="Index"
class="btn btn-default btn-sm">취소</a>
</div>
</div>
</form>
</section>
</div>
<div class="col-md-4">
</div>
</div>
@section Scripts {
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
▶ Views/User/Login.cshtml
@model UserModel
@{
ViewData["Title"] = "로그인 페이지";
}
<h2>@ViewData["Title"]</h2>
<div class="row">
<div class="col-md-8">
<section>
<form asp-controller="User" asp-action="Login" asp-route-returnurl="@ViewData["ReturnURL"]"
method="post"
class="form-horizontal">
<h4>사용자 ID와 패스워드를 입력해 주시기 바랍니다.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="UserID" class="col-md-2 control-label"></label>
<div class="col-md-6">
<input asp-for="UserID" class="form-control" placeholder="사용자 ID" />
<span asp-validation-for="UserID" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Password" class="col-md-2 control-label"></label>
<div class="col-md-6">
<input type="password" asp-for="Password" class="form-control" placeholder="패스워드" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-6">
<button type="submit" class="btn btn-primary btn-lg">로그인</button>
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnURL"]"
class="btn btn-default btn-sm">
회원 가입
</a>
</div>
</div>
</form>
</section>
</div>
<div class="col-md-4">
</div>
</div>
@section Scripts {
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
▶ Views/User/Logout.cshtml
<h2>로그아웃 페이지</h2>
▶ Views/User/UserInformation.cshtml
<h2>회원 정보 페이지</h2>
<h4>@User.FindFirst("UserID").Value 님의 정보는 아래와 같습니다.</h4>
<hr />
▶ Views/User/Greetings.cshtml
<h2>인증된 사용자만 볼 수 있는 페이지</h2>
▶ Views/User/Forbidden.cshtml
<h2>접근 권한이 없습니다.</h2>
▶ Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TestProject.Models;
using TestProject.Settings;
namespace TestProject
{
/// <summary>
/// 시작
/// </summary>
public class Startup
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 구성 - Configuration
/// <summary>
/// 구성
/// </summary>
public IConfiguration Configuration { get; }
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Startup(configuration)
/// <summary>
/// 생성자
/// </summary>
/// <param name="configuration">구성</param>
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 서비스 컬렉션 구성하기 - ConfigureServices(services)
/// <summary>
/// 서비스 컬렉션 구성하기
/// </summary>
/// <param name="services">서비스 컬렉션</param>
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
services.Configure<MainSettings>(Configuration.GetSection(nameof(MainSettings)));
services.AddTransient<IUserRepository, UserRepository>();
services.AddAuthentication("CookieAuthentication")
.AddCookie
(
"CookieAuthentication",
options =>
{
options.Cookie.Name = "UserLoginCookie";
options.LoginPath = new PathString("/User/Login");
options.AccessDeniedPath = new PathString("/User/Forbidden");
}
);
services.AddAuthorization
(
options =>
{
options.AddPolicy("Users", policy => policy.RequireRole("Users"));
options.AddPolicy
(
"Administrators",
policy => policy.RequireRole("Users").RequireClaim
(
"UserID",
Configuration.GetSection(nameof(MainSettings)).GetSection("SiteAdministrator").Value
)
);
}
);
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();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints
(
endpoints =>
{
endpoints.MapControllerRoute
(
name : "default",
pattern : "{controller=Home}/{action=Index}/{id?}"
);
}
);
}
#endregion
}
}
※ Database 폴더에 있는 TestDB.mdf를 SQL Server나 Local DB에 연결해야 한다.
※ Startup 클래스의 ConfigureServices 메소드에서 Administrators 역할을 추가했으나 사용하지는 않았다.
728x90
반응형
그리드형(광고전용)
'C# > ASP.NET MVC' 카테고리의 다른 글
[C#/ASP.NET MVC] Kestrel 사용시 업로드 파일 크기 설정하기 (2) (0) | 2020.10.14 |
---|---|
[C#/ASP.NET MVC] Kestrel 사용시 업로드 파일 크기 설정하기 (1) (0) | 2020.10.14 |
[C#/ASP.NET MVC] IIS Express 사용시 업로드 파일 크기 설정하기 (0) | 2020.10.14 |
[C#/ASP.NET MVC] 파일 업로드 액션 메소드에서 파일 정보를 전달받는 매개 변수의 데이터 타입 설정하기 (0) | 2020.10.14 |
[C#/ASP.NET MVC] JWT(Json Web Token) 인증 사용하기 (0) | 2020.10.13 |
[C#/ASP.NET MVC] 쿠키(Cookie) 인증 사용하기 (0) | 2020.10.12 |
[C#/ASP.NET MVC] 누겟 설치 : Microsoft.AspNetCore.Authentication.Cookies (0) | 2020.10.11 |
[C#/ASP.NET MVC] RequestFormLimitsAttribute 클래스 : 폼에서 특정 제한 설정하기 (0) | 2020.10.11 |
[C#/ASP.NET MVC] web.config 파일에서 최대 허용 컨텐트 길이 설정하기 (0) | 2020.10.11 |
[C#/ASP.NET MVC] KestrelServerOptions 클래스 : Limits 속성을 사용해 최대 요청 BODY 크기 설정하기 (0) | 2020.10.11 |
[C#/ASP.NET MVC] IISServerOptions 클래스 : MaxRequestBodySize 속성을 사용해 최대 요청 BODY 크기 설정하기 (0) | 2020.10.11 |
댓글을 달아 주세요