728x90
반응형
728x170
[TestAuthorizationServer 프로젝트]
▶ Properties/launchSettings.json
{
"iisSettings" :
{
"windowsAuthentication" : false,
"anonymousAuthentication" : true,
"iisExpress" :
{
"applicationUrl" : "http://localhost:50000",
"sslPort" : 44300
}
},
"profiles" :
{
"IIS Express" :
{
"commandName" : "IISExpress",
"launchBrowser" : true,
"environmentVariables" :
{
"ASPNETCORE_ENVIRONMENT" : "Development"
}
},
"TestAuthorizationServer" :
{
"commandName" : "Project",
"launchBrowser" : true,
"applicationUrl" : "https://localhost:5001;http://localhost:5000",
"environmentVariables" :
{
"ASPNETCORE_ENVIRONMENT" : "Development"
}
}
}
}
728x90
▶ ConstantHelper.cs
namespace TestAuthorizationServer
{
/// <summary>
/// 상수 헬퍼
/// </summary>
public class ConstantHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 발급자
/// </summary>
public const string Issuer = Audiance;
/// <summary>
/// 청중
/// </summary>
public const string Audiance = "https://localhost:44300/";
/// <summary>
/// 패스워드
/// </summary>
public const string Password = "not_too_short_secret_otherwise_it_might_error";
#endregion
}
}
300x250
▶ Startup.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;
using System.Threading.Tasks;
namespace TestAuthorizationServer
{
/// <summary>
/// 시작
/// </summary>
public class Startup
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 서비스 컬렉션 구성하기 - ConfigureServices(services)
/// <summary>
/// 서비스 컬렉션 구성하기
/// </summary>
/// <param name="services">서비스 컬렉션</param>
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("OAuth")
.AddJwtBearer
(
"OAuth",
options =>
{
byte[] passwordByteArray = Encoding.UTF8.GetBytes(ConstantHelper.Password);
SymmetricSecurityKey key = new SymmetricSecurityKey(passwordByteArray);
options.Events = new JwtBearerEvents()
{
OnMessageReceived = context =>
{
if(context.Request.Query.ContainsKey("access_token"))
{
context.Token = context.Request.Query["access_token"];
}
return Task.CompletedTask;
}
};
options.TokenValidationParameters = new TokenValidationParameters()
{
ClockSkew = TimeSpan.Zero,
ValidIssuer = ConstantHelper.Issuer,
ValidAudience = ConstantHelper.Audiance,
IssuerSigningKey = key
};
}
);
services.AddControllersWithViews()
.AddRazorRuntimeCompilation();
}
#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
using Microsoft.AspNetCore.Mvc;
namespace TestAuthorizationServer.Controllers
{
/// <summary>
/// 홈 컨트롤러
/// </summary>
public class HomeController : Controller
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 페이지 처리하기 - Index()
/// <summary>
/// 인덱스 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
public IActionResult Index()
{
return View();
}
#endregion
}
}
▶ Controllers/OAuthController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TestAuthorizationServer.Controllers
{
/// <summary>
/// OAUTH 컨트롤러
/// </summary>
public class OAuthController : Controller
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 로그인 페이지 처리하기 - Login(client_id, scope, response_type, redirect_uri, state)
/// <summary>
/// 로그인 페이지 처리하기
/// </summary>
/// <param name="client_id">클라이언트 ID</param>
/// <param name="scope">범위</param>
/// <param name="response_type">인증 플로우 타입</param>
/// <param name="redirect_uri">재전송 URI</param>
/// <param name="state">상태</param>
/// <returns>액션 결과</returns>
[HttpGet]
public IActionResult Login(string client_id, string scope, string response_type, string redirect_uri, string state)
{
QueryBuilder queryBuilder = new QueryBuilder();
queryBuilder.Add("redirectURI", redirect_uri);
queryBuilder.Add("state" , state );
return View(model : queryBuilder.ToString());
}
#endregion
#region 로그인 페이지 처리하기 - Login(userName, password, redirectURI, state)
/// <summary>
/// 로그인 페이지 처리하기
/// </summary>
/// <param name="userName">사용자명</param>
/// <param name="password">패스워드</param>
/// <param name="redirectURI">재전송 URI</param>
/// <param name="state">상태</param>
/// <returns>액션 결과</returns>
[HttpPost]
public IActionResult Login(string userName, string password, string redirectURI, string state)
{
const string code = "TESTCODE"; // 사용자명과 패스워드에 따라 code를 설정한다.
QueryBuilder queryBuilder = new QueryBuilder();
queryBuilder.Add("code" , code );
queryBuilder.Add("state", state);
return Redirect($"{redirectURI}{queryBuilder.ToString()}");
}
#endregion
#region 토큰 페이지 처리하기 - Token(grant_type, code, redirect_uri, client_id, refresh_token)
/// <summary>
/// 토큰 페이지 처리하기
/// </summary>
/// <param name="grant_type">그랜트 타입</param>
/// <param name="code">코드</param>
/// <param name="redirect_uri">재전송 URI</param>
/// <param name="client_id">클라이언트 ID</param>
/// <param name="refresh_token">갱신 토큰</param>
/// <returns></returns>
public async Task<IActionResult> Token(string grant_type, string code, string redirect_uri, string client_id, string refresh_token)
{
// 그랜트 타입, 코드, 갱신 토큰 값에 따라 JWT를 발행한다.
List<Claim> claimList = new List<Claim>()
{
new Claim(JwtRegisteredClaimNames.Sub , "ID0001" ),
new Claim(JwtRegisteredClaimNames.Birthdate, "1990-01-01" ),
new Claim(JwtRegisteredClaimNames.Email , "test@daum.net"),
new Claim(JwtRegisteredClaimNames.Gender , "Male" ),
new Claim("CompanyGroup" , "영업1그룹" ),
new Claim("CompanyDepartment" , "영업1팀" ),
new Claim("CompanyTitle" , "대리" ),
new Claim("EmployeeID" , "EMP0001" ),
new Claim("EmployeeName" , "홍길동" )
};
byte[] passwordByteArray = Encoding.UTF8.GetBytes(ConstantHelper.Password);
SymmetricSecurityKey key = new SymmetricSecurityKey(passwordByteArray);
string algorithm = SecurityAlgorithms.HmacSha256;
SigningCredentials signingCredentials = new SigningCredentials(key, algorithm);
JwtSecurityToken token = new JwtSecurityToken
(
ConstantHelper.Issuer,
ConstantHelper.Audiance,
claimList,
notBefore : DateTime.Now,
expires : grant_type == "refresh_token" ? DateTime.Now.AddMinutes(5) : DateTime.Now.AddMilliseconds(1), // 테스트용 코드
signingCredentials
);
string access_token = new JwtSecurityTokenHandler().WriteToken(token);
var responseObject = new
{
access_token,
token_type = "Bearer",
refresh_token = "REFRESH_TOKEN_SAMPLE_VALUE",
raw_claim = "oauthTurorial"
};
string responseJSON = JsonConvert.SerializeObject(responseObject);
byte[] responseByteArray = Encoding.UTF8.GetBytes(responseJSON);
await Response.Body.WriteAsync(responseByteArray, 0, responseByteArray.Length);
return Redirect(redirect_uri);
}
#endregion
#region 검증 페이지 처리하기 - Validate()
/// <summary>
/// 검증 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
[Authorize]
public IActionResult Validate()
{
if(HttpContext.Request.Query.TryGetValue("access_token", out var accessToken))
{
return Ok();
}
return BadRequest();
}
#endregion
}
}
▶ Controllers/SecretController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
namespace TestAuthorizationServer.Controllers
{
/// <summary>
/// 비밀 컨트롤러
/// </summary>
public class SecretController : Controller
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 페이지 처리하기 - Index()
/// <summary>
/// 인덱스 페이지 처리하기
/// </summary>
/// <returns>문자열</returns>
[Authorize]
public IActionResult Index()
{
return Json($"인증 서버 비밀 메시지 {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
}
#endregion
}
}
▶ Views/Home/Index.cshtml
<h1>인증 서버 인덱스 페이지</h1>
<hr />
▶ Views/OAuth/Login.cshtml
@model string
@{
var url = $"/OAuth/Login{Model}";
}
<h1>인증 서버 로그인 페이지</h1>
<hr />
<form action="@url" method="post">
<p>사용자명 <input type="text" name="userName" /></p>
<p>패스워드 <input type="password" name="password" /></p>
<p><input type="submit" value="로그인" /></p>
</form>
[TestAPIServer 프로젝트]
▶ Properties/launchSettings.json
{
"iisSettings" :
{
"windowsAuthentication" : false,
"anonymousAuthentication" : true,
"iisExpress" :
{
"applicationUrl" : "http://localhost:50010",
"sslPort" : 44310
}
},
"profiles" :
{
"IIS Express" :
{
"commandName" : "IISExpress",
"launchBrowser" : true,
"environmentVariables" :
{
"ASPNETCORE_ENVIRONMENT" : "Development"
}
},
"TestAPIServer" :
{
"commandName" : "Project",
"launchBrowser" : true,
"applicationUrl" : "https://localhost:5001;http://localhost:5000",
"environmentVariables" :
{
"ASPNETCORE_ENVIRONMENT" : "Development"
}
}
}
}
▶ Requirement/JWTRequirement.cs
using Microsoft.AspNetCore.Authorization;
namespace TestAPIServer.Requirement
{
/// <summary>
/// JWT 요청
/// </summary>
public class JWTRequirement : IAuthorizationRequirement
{
}
}
▶ Requirement/JWTRequirementAuthorizationHandler.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace TestAPIServer.Requirement
{
/// <summary>
/// JWT 요청 권한 핸들러
/// </summary>
public class JWTRequirementAuthorizationHandler : AuthorizationHandler<JWTRequirement>
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// HTTP 클라이언트
/// </summary>
private readonly HttpClient httpClient;
/// <summary>
/// HTTP 컨텍스트
/// </summary>
private readonly HttpContext httpContext;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - JWTRequirementAuthorizationHandler(factory, accessor)
/// <summary>
/// 생성자
/// </summary>
/// <param name="factory">HTTP 클라이언트 팩토리</param>
/// <param name="accessor">HTTP 컨텍스트 접근자</param>
public JWTRequirementAuthorizationHandler(IHttpClientFactory factory, IHttpContextAccessor accessor)
{
this.httpClient = factory.CreateClient();
this.httpContext = accessor.HttpContext;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 요청 처리하기 (비동기) - HandleRequirementAsync(context, requirement)
/// <summary>
/// 요청 처리하기 (비동기)
/// </summary>
/// <param name="context">컨텍스트</param>
/// <param name="requirement">요청</param>
/// <returns>태스크</returns>
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, JWTRequirement requirement)
{
if(this.httpContext.Request.Headers.TryGetValue("Authorization", out var authorizationHeaderValue))
{
string accessToken = authorizationHeaderValue.ToString().Split(' ')[1];
string url = $"https://localhost:44300/oauth/validate?access_token={accessToken}";
HttpResponseMessage response = await this.httpClient.GetAsync(url);
if(response.StatusCode == HttpStatusCode.OK)
{
context.Succeed(requirement);
}
}
}
#endregion
}
}
▶ CustomAuthenticationHandler.cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
namespace TestAPIServer
{
/// <summary>
/// 커스텀 인증 핸들러
/// </summary>
public class CustomAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - CustomAuthenticationHandler(options, loggerFactory, urlEncoder, systemClock)
/// <summary>
/// 생성자
/// </summary>
/// <param name="options">옵션</param>
/// <param name="loggerFactory">로그 기록기 팩토리</param>
/// <param name="urlEncoder">URL 인코더</param>
/// <param name="systemClock">시스템 시계</param>
public CustomAuthenticationHandler
(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory loggerFactory,
UrlEncoder urlEncoder,
ISystemClock systemClock
) : base(options, loggerFactory, urlEncoder, systemClock)
{
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 인증 처리하기 (비동기) - HandleAuthenticateAsync()
/// <summary>
/// 인증 처리하기 (비동기)
/// </summary>
/// <returns>인증 결과</returns>
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.Fail("Failed Authentication"));
}
#endregion
}
}
▶ Startup.cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TestAPIServer.Requirement;
namespace TestAPIServer
{
/// <summary>
/// 시작
/// </summary>
public class Startup
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 서비스 컬렉션 구성하기 - ConfigureServices(services)
/// <summary>
/// 서비스 컬렉션 구성하기
/// </summary>
/// <param name="services">서비스 컬렉션</param>
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("DefaultAuth")
.AddScheme<AuthenticationSchemeOptions, CustomAuthenticationHandler>("DefaultAuth", null);
services.AddAuthorization
(
options =>
{
var defaultAuthBuilder = new AuthorizationPolicyBuilder();
var defaultAuthPolicy = defaultAuthBuilder
.AddRequirements(new JWTRequirement())
.Build();
options.DefaultPolicy = defaultAuthPolicy;
}
);
services.AddScoped<IAuthorizationHandler, JWTRequirementAuthorizationHandler>();
services.AddHttpClient()
.AddHttpContextAccessor();
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
using Microsoft.AspNetCore.Mvc;
namespace TestAPIServer.Controllers
{
/// <summary>
/// 홈 컨트롤러
/// </summary>
public class HomeController : Controller
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 페이지 처리하기 - Index()
/// <summary>
/// 인덱스 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
public IActionResult Index()
{
return View();
}
#endregion
}
}
▶ Controllers/SecretController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
namespace TestAPIServer.Controllers
{
/// <summary>
/// 비밀 컨트롤러
/// </summary>
public class SecretController : Controller
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 페이지 구하기 - Index()
/// <summary>
/// 인덱스 페이지 구하기
/// </summary>
/// <returns>문자열</returns>
[Authorize]
public IActionResult Index()
{
return Json($"API 서버 비밀 메시지 {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
}
#endregion
}
}
▶ Views/Home/Index.cshtml
<h1>API 서버 인덱스 페이지</h1>
<hr />
[TestClient 프로젝트]
▶ Properties/launchSettings.json
{
"iisSettings" :
{
"windowsAuthentication" : false,
"anonymousAuthentication" : true,
"iisExpress" :
{
"applicationUrl" : "http://localhost:50030",
"sslPort" : 44320
}
},
"profiles" :
{
"IIS Express" :
{
"commandName" : "IISExpress",
"launchBrowser" : true,
"environmentVariables" :
{
"ASPNETCORE_ENVIRONMENT" : "Development"
}
},
"TestClient" :
{
"commandName" : "Project",
"launchBrowser" : true,
"applicationUrl" : "https://localhost:5001;http://localhost:5000",
"environmentVariables" :
{
"ASPNETCORE_ENVIRONMENT" : "Development"
}
}
}
}
▶ Startup.cs
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using IdentityModel;
namespace TestClient
{
/// <summary>
/// 시작
/// </summary>
public class Startup
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 서비스 컬렉션 구성하기 - ConfigureServices(services)
/// <summary>
/// 서비스 컬렉션 구성하기
/// </summary>
/// <param name="services">서비스 컬렉션</param>
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication
(
options =>
{
options.DefaultAuthenticateScheme = "TestClientCookie";
options.DefaultSignInScheme = "TestClientCookie";
options.DefaultChallengeScheme = "TestServer";
}
)
.AddCookie("TestClientCookie")
.AddOAuth
(
"TestServer",
options =>
{
options.ClientId = "CLIENTID0001";
options.ClientSecret = "CLIENTSECRET0001";
options.CallbackPath = "/oauth/callback";
options.AuthorizationEndpoint = "https://localhost:44300/oauth/login";
options.TokenEndpoint = "https://localhost:44300/oauth/token";
options.SaveTokens = true;
options.Events = new OAuthEvents()
{
OnCreatingTicket = context =>
{
string accessToken = context.AccessToken;
string payload = accessToken.Split('.')[1];
byte[] payloadByteArray = Base64Url.Decode(payload);
string json = Encoding.UTF8.GetString(payloadByteArray);
Dictionary<string, string> claimDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
foreach(KeyValuePair<string, string> claimKeyValuePair in claimDictionary)
{
context.Identity.AddClaim(new Claim(claimKeyValuePair.Key, claimKeyValuePair.Value));
}
return Task.CompletedTask;
}
};
}
);
services.AddHttpClient();
services.AddControllersWithViews()
.AddRazorRuntimeCompilation();
}
#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
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TestClient.Controllers
{
/// <summary>
/// 홈 컨트롤러
/// </summary>
public class HomeController : Controller
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// HTTP 클라이언트 팩토리
/// </summary>
private readonly IHttpClientFactory factory;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - HomeController(factory)
/// <summary>
/// 생성자
/// </summary>
/// <param name="factory">HTTP 클라이언트 팩토리</param>
public HomeController(IHttpClientFactory factory)
{
this.factory = factory;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 인덱스 페이치 처리하기 - Index()
/// <summary>
/// 인덱스 페이치 처리하기
/// </summary>
/// <returns>액션 결과</returns>
public IActionResult Index()
{
return View();
}
#endregion
#region 비밀 페이지 처리하기 - Secret()
/// <summary>
/// 비밀 페이지 처리하기
/// </summary>
/// <returns>액션 결과</returns>
[Authorize]
public async Task<IActionResult> Secret()
{
HttpResponseMessage authorizationServerResponse = await SecureRequest(() => GETSecureRequest("https://localhost:44300/secret/index"));
if(authorizationServerResponse.IsSuccessStatusCode)
{
string result = await authorizationServerResponse.Content.ReadAsAsync<string>();
ViewData["AuthorizationServerData"] = result;
}
HttpResponseMessage apiServerResponse = await SecureRequest(() => GETSecureRequest("https://localhost:44310/secret/index"));
if(apiServerResponse.IsSuccessStatusCode)
{
string result = await apiServerResponse.Content.ReadAsAsync<string>();
ViewData["APIServerData"] = result;
}
return View();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region GET 보안 요청하기 - GETSecureRequest(url)
/// <summary>
/// GET 보안 요청하기
/// </summary>
/// <param name="url">URL</param>
/// <returns>HTTP 응답 메시지</returns>
private async Task<HttpResponseMessage> GETSecureRequest(string url)
{
string accessToken = await HttpContext.GetTokenAsync("access_token");
HttpClient client = this.factory.CreateClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
HttpResponseMessage response = await client.GetAsync(url);
return response;
}
#endregion
#region 액세스 토큰 갱신하기 - RefreshAccessToken()
/// <summary>
/// 액세스 토큰 갱신하기
/// </summary>
/// <returns>태스크</returns>
private async Task RefreshAccessToken()
{
string refreshToken = await HttpContext.GetTokenAsync("refresh_token");
HttpClient httpClient = this.factory.CreateClient();
Dictionary<string, string> requestDictionary = new Dictionary<string, string>
{
["grant_type" ] = "refresh_token",
["refresh_token"] = refreshToken
};
string requestURL = "https://localhost:44300/oauth/token";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestURL)
{
Content = new FormUrlEncodedContent(requestDictionary)
};
string sourceAuthorization = "username:password";
byte[] sourceAuthorizationByteArray = Encoding.UTF8.GetBytes(sourceAuthorization);
var targetAuthorization = Convert.ToBase64String(sourceAuthorizationByteArray);
request.Headers.Add("Authorization", $"Basic {targetAuthorization}");
HttpResponseMessage response = await httpClient.SendAsync(request);
string responseJSON = await response.Content.ReadAsStringAsync();
Dictionary<string, string> responseDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseJSON);
string newAccessToken = responseDictionary.GetValueOrDefault("access_token" );
string newRefreshToken = responseDictionary.GetValueOrDefault("refresh_token");
AuthenticateResult authenticateResult = await HttpContext.AuthenticateAsync("TestClientCookie");
authenticateResult.Properties.UpdateTokenValue("access_token" , newAccessToken );
authenticateResult.Properties.UpdateTokenValue("refresh_token", newRefreshToken);
await HttpContext.SignInAsync("TestClientCookie", authenticateResult.Principal, authenticateResult.Properties);
}
#endregion
#region 보안 요청하기 - SecureRequest(requestFunction)
/// <summary>
/// 보안 요청하기
/// </summary>
/// <param name="requestFunction">요청 함수</param>
/// <returns>HTTP 응답 메시지 태스크</returns>
private async Task<HttpResponseMessage> SecureRequest(Func<Task<HttpResponseMessage>> requestFunction)
{
HttpResponseMessage response = await requestFunction();
if(response.StatusCode == HttpStatusCode.Unauthorized)
{
await RefreshAccessToken();
response = await requestFunction();
}
return response;
}
#endregion
}
}
▶ Views/Home/Index.cshtml
<h1>클라이언트 인덱스 페이지</h1>
<hr />
▶ Views/Home/Secret.cshtml
<h1>클라이언트 비밀 페이지</h1>
<hr />
<p>인증 서버 데이터 : @ViewData["AuthorizationServerData"]</p>
<p>API 서버 데이터 : @ViewData["APIServerData"]</p>
728x90
반응형
그리드형(광고전용)
'C# > ASP.NET MVC' 카테고리의 다른 글
[C#/ASP.NET MVC] RazorPageBase 클래스 : User 속성 사용하기 (0) | 2020.11.03 |
---|---|
[C#/ASP.NET MVC] dotnet run 명령 : 환경 변수를 설정하고 프로그램 실행하기 (0) | 2020.11.03 |
[C#/ASP.NET MVC] dotnet new -i 명령 : IdentityServer4 템플리트 설치하기 (0) | 2020.11.03 |
[C#/ASP.NET MVC] IdentityServer4 인증 사용하기 (개념 학습용) (0) | 2020.11.03 |
[C#/ASP.NET MVC] AREA 사용하기 (0) | 2020.11.03 |
[C#/ASP.NET MVC] OAuth 인증 사용하기 (액세스 토큰 갱신 추가) (0) | 2020.11.03 |
[C#/ASP.NET MVC] OAuth 인증 사용하기 (API 서버 추가) (0) | 2020.11.02 |
[C#/ASP.NET MVC] 누겟 설치 : IdentityModel (0) | 2020.11.02 |
[C#/ASP.NET MVC] OAuth 인증 사용하기 (0) | 2020.11.01 |
[C#/ASP.NET MVC] 누겟 설치 : Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore (0) | 2020.11.01 |
[C#/ASP.NET MVC] StatusCodePagesExtensions 클래스 : UseStatusCodePages 확장 메소드에서 람다식 사용하기 (0) | 2020.11.01 |
댓글을 달아 주세요