■ WEB API에서 JWT(Json Web Token) 인증을 사용하는 방법을 보여준다.
[TestLibrary 프로젝트]
▶ User.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 |
namespace TestLibrary { /// <summary> /// 사용자 /// </summary> public class User { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 사용자명 - UserName /// <summary> /// 사용자명 /// </summary> public string UserName { get; set; } #endregion #region 패스워드 - Password /// <summary> /// 패스워드 /// </summary> public string Password { get; set; } #endregion #region 사용자 역할 - UserRole /// <summary> /// 사용자 역할 /// </summary> public string UserRole { get; set; } #endregion } } |
▶ WeatherForecast.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 |
using System; namespace TestLibrary { /// <summary> /// 기상 예보 /// </summary> public class WeatherForecast { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 일자 - Date /// <summary> /// 일자 /// </summary> public DateTime Date { get; set; } #endregion #region 섭씨 온도 - TemperatureC /// <summary> /// 섭씨 온도 /// </summary> public int TemperatureC { get; set; } #endregion #region 화씨 온도 - TemperatureF /// <summary> /// 화씨 온도 /// </summary> public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); #endregion #region 요약 - Summary /// <summary> /// 요약 /// </summary> public string Summary { get; set; } #endregion } } |
[TestServer 프로젝트]
▶ appsettings.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "Logging" : { "LogLevel" : { "Default" : "Information", "Microsoft" : "Warning", "Microsoft.Hosting.Lifetime" : "Information" } }, "AllowedHosts" : "*", "JWT" : { "SecretKey" : "abcdefghijklmnopqrstuvwxyz1234567890", "Issuer" : "https://localhost:44316/", "Audience" : "https://localhost:44316/" } } |
▶ MultipleRoleAuthorizeFilter.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 |
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace TestServer.Tools { /// <summary> /// 복수 역할 권한 확인 필터 /// </summary> public class MultipleRoleAuthorizeFilter : IAsyncAuthorizationFilter { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 권한 서비스 /// </summary> private readonly IAuthorizationService authorizationService; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 정책 리스트 - PolicyList /// <summary> /// 정책 리스트 /// </summary> public string PolicyList { get; private set; } #endregion #region AND 적용 여부 - ApplyAnd /// <summary> /// AND 적용 여부 /// </summary> public bool ApplyAnd { get; private set; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MultipleRoleAuthorizeFilter(policyList, applyAnd, authorizationService) /// <summary> /// 생성자 /// </summary> /// <param name="policyList">정책 리스트</param> /// <param name="applyAnd">AND 적용 여부</param> /// <param name="authorizationService">권한 서비스</param> public MultipleRoleAuthorizeFilter(string policyList, bool applyAnd, IAuthorizationService authorizationService) { this.authorizationService = authorizationService; PolicyList = policyList; ApplyAnd = applyAnd; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 권한 확인시 처리하기 (비동기) - OnAuthorizationAsync(context) /// <summary> /// 권한 확인시 처리하기 (비동기) /// </summary> /// <param name="context">컨텍스트</param> /// <returns>태스크</returns> public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { List<string> list = PolicyList.Split(";").ToList(); if(ApplyAnd) { foreach(string policy in list) { AuthorizationResult result = await authorizationService.AuthorizeAsync(context.HttpContext.User, policy); if(!result.Succeeded) { context.Result = new UnauthorizedResult(); // new ForbidResult(); return; } } } else { foreach(string policy in list) { AuthorizationResult result = await authorizationService.AuthorizeAsync(context.HttpContext.User, policy); if(result.Succeeded) { return; } } context.Result = new UnauthorizedResult(); // new ForbidResult(); return; } } #endregion } } |
▶ MultipleRoleAuthorizeAttribute.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 |
using Microsoft.AspNetCore.Mvc; namespace TestServer.Tools { /// <summary> /// 복수 역할 권한 확인 어트리브튜 /// </summary> public class MultipleRoleAuthorizeAttribute : TypeFilterAttribute { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MultipleRoleAuthorizeAttribute(policyList, applyAnd) /// <summary> /// 생성자 /// </summary> /// <param name="policyList">정책 리스트</param> /// <param name="applyAnd">AND 적용 여부</param> public MultipleRoleAuthorizeAttribute(string policyList, bool applyAnd = false) : base(typeof(MultipleRoleAuthorizeFilter)) { Arguments = new object[] { policyList, applyAnd }; } #endregion } } |
▶ Policy.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 |
using Microsoft.AspNetCore.Authorization; namespace TestServer.Tools { /// <summary> /// 정책 /// </summary> public class Policy { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Instance //////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 관리자 /// </summary> public const string Administrator = "Administrator"; /// <summary> /// 사용자 /// </summary> public const string User = "User"; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 관리자 권한 정책 구하기 - GetAdministratorAuthorizationPolicy() /// <summary> /// 관리자 권한 정책 구하기 /// </summary> /// <returns>관리자 권한 정책</returns> public static AuthorizationPolicy GetAdministratorAuthorizationPolicy() { return new AuthorizationPolicyBuilder().RequireAuthenticatedUser().RequireRole(Administrator).Build(); } #endregion #region 사용자 권한 정책 구하기 - GetUserAuthorizationPolicy() /// <summary> /// 사용자 권한 정책 구하기 /// </summary> /// <returns>사용자 권한 정책</returns> public static AuthorizationPolicy GetUserAuthorizationPolicy() { return new AuthorizationPolicyBuilder().RequireAuthenticatedUser().RequireRole(User).Build(); } #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 132 133 134 135 136 137 138 139 140 141 |
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using System; using System.Text; using TestServer.Tools; namespace TestServer { /// <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(serviceCollection) /// <summary> /// 서비스 컬렉션 구성하기 /// </summary> /// <param name="serviceCollection">서비스 컬렉션</param> public void ConfigureServices(IServiceCollection serviceCollection) { serviceCollection.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer ( option => { option.RequireHttpsMetadata = false; option.SaveToken = true; option.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = Configuration["JWT:Issuer"], ValidAudience = Configuration["JWT:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:SecretKey"])), ClockSkew = TimeSpan.Zero }; } ); serviceCollection.AddAuthorization ( option => { option.AddPolicy(Policy.Administrator, Policy.GetAdministratorAuthorizationPolicy()); option.AddPolicy(Policy.User , Policy.GetUserAuthorizationPolicy() ); } ); serviceCollection.AddControllers(); serviceCollection.AddSwaggerGen ( option => { option.SwaggerDoc("v1", new OpenApiInfo { Title = "TestServer", Version = "v1" }); } ); } #endregion #region 구성하기 - Configure(applicationBuilder, environment) /// <summary> /// 구성하기 /// </summary> /// <param name="applicationBuilder">애플리케이션 빌더</param> /// <param name="environment">환경</param> public void Configure(IApplicationBuilder applicationBuilder, IWebHostEnvironment environment) { if(environment.IsDevelopment()) { applicationBuilder.UseDeveloperExceptionPage(); applicationBuilder.UseSwagger(); applicationBuilder.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TestServer v1")); } applicationBuilder.UseHttpsRedirection(); applicationBuilder.UseRouting(); applicationBuilder.UseAuthentication(); applicationBuilder.UseAuthorization(); applicationBuilder.UseEndpoints ( endpoints => { endpoints.MapControllers(); } ); } #endregion } } |
▶ LoginController.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 |
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using TestLibrary; using TestServer.Tools; namespace TestServer.Controllers { /// <summary> /// 로그인 컨트롤러 /// </summary> [ApiController] [Route("[controller]")] public class LoginController : ControllerBase { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 사용자 딕셔너리 /// </summary> private static Dictionary<string, User> _userDictionary = new Dictionary<string, User>(); #endregion ////////////////////////////////////////////////////////////////////////////////////////// Instance //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 구성 /// </summary> private readonly IConfiguration configuration; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Static #region 생성자 - LoginController() /// <summary> /// 생성자 /// </summary> static LoginController() { _userDictionary.Add("admin", new User { UserName = "admin", Password = "1234", UserRole = Policy.Administrator }); _userDictionary.Add("user1", new User { UserName = "user1", Password = "1234", UserRole = Policy.User }); _userDictionary.Add("user2", new User { UserName = "user2", Password = "1234", UserRole = Policy.User }); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Instance //////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - LoginController(configuration) /// <summary> /// 생성자 /// </summary> /// <param name="configuration">구성</param> public LoginController(IConfiguration configuration) { this.configuration = configuration; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 로그인하기 - Login(loginUser) /// <summary> /// 로그인하기 /// </summary> /// <param name="loginUser">로그인 사용자</param> /// <returns>액션 결과</returns> [HttpPost] [AllowAnonymous] public IActionResult Login([FromBody] User loginUser) { IActionResult actionResult = Unauthorized(); User user = AuthenticateUser(loginUser); if(user != null) { string token = GenerateJWTToken(user); actionResult = Ok(token); } return actionResult; } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 사용자 인증하기 - AuthenticateUser(loginUser) /// <summary> /// 사용자 인증하기 /// </summary> /// <param name="loginUser">로그인 사용자</param> /// <returns>인증 사용자</returns> private User AuthenticateUser(User loginUser) { if(_userDictionary.ContainsKey(loginUser.UserName)) { User user = _userDictionary[loginUser.UserName]; if(user.Password == loginUser.Password) { return user; } else { return null; } } else { return null; } } #endregion #region JWT 토큰 생성하기 - GenerateJWTToken(user) /// <summary> /// JWT 토큰 생성하기 /// </summary> /// <param name="user">사용자</param> /// <returns>JWT 토큰</returns> private string GenerateJWTToken(User user) { byte[] keyByteArray = Encoding.UTF8.GetBytes(configuration["JWT:SecretKey"]); SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(keyByteArray); SigningCredentials credentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256); Claim[] claimArray = new[] { new Claim(JwtRegisteredClaimNames.Sub, user.UserName ), new Claim("role" , user.UserRole ), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; JwtSecurityToken token = new JwtSecurityToken ( issuer : configuration["JWT:Issuer"], audience : configuration["JWT:Audience"], claims : claimArray, expires : DateTime.Now.AddHours(1), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); } #endregion } } |
▶ WeatherForecastController.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 |
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using TestLibrary; using TestServer.Tools; namespace TestServer.Controllers { /// <summary> /// 기상 예보 컨트롤러 /// </summary> [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 요약 배열 /// </summary> private static readonly string[] _summaryArray = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; #endregion ////////////////////////////////////////////////////////////////////////////////////////// Instance //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 로거 /// </summary> private readonly ILogger<WeatherForecastController> logger; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - WeatherForecastController(logger) /// <summary> /// 생성자 /// </summary> /// <param name="logger">로거</param> public WeatherForecastController(ILogger<WeatherForecastController> logger) { this.logger = logger; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 구하기 - Get() /// <summary> /// 구하기 /// </summary> /// <returns>기상 예보 열거 가능형</returns> [HttpGet] [MultipleRoleAuthorize("Administrator;User")] public IEnumerable<WeatherForecast> Get() { Random random = new Random(); IEnumerable<WeatherForecast> enumerable = Enumerable.Range(1, 5) .Select ( index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = random.Next(-20, 55), Summary = _summaryArray[random.Next(_summaryArray.Length)] } ) .ToArray(); return enumerable; } #endregion } } |
[TestClient 프로젝트]
▶ 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 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 |
using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using TestLibrary; namespace TestClient { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> static void Main() { User user = new User { UserName = "admin", Password = "1234"}; string token = Login("https://localhost:44316/Login", user).GetAwaiter().GetResult(); Console.WriteLine($"JWT 토큰 : {token}"); Console.WriteLine("--------------------------------------------------"); IEnumerable<WeatherForecast> result = Test("https://localhost:44316/WeatherForecast", token).GetAwaiter().GetResult(); if(result != null) { foreach(WeatherForecast item in result) { Console.WriteLine(item.Summary); } } Console.WriteLine("--------------------------------------------------"); Console.WriteLine("아무 키나 눌러 주시기 바랍니다."); Console.ReadKey(true); } #endregion #region HTTP 클라이언트 구하기 - GetHTTPClient(useCookie, baseAddress, tokenShema, token) /// <summary> /// HTTP 클라이언트 구하기 /// </summary> /// <param name="useCookie">쿠키 사용 여부</param> /// <param name="baseAddress">기본 주소</param> /// <param name="tokenShema">토큰 스키마</param> /// <param name="token">토큰</param> /// <returns>HTTP 클라이언트</returns> private static HttpClient GetHTTPClient(bool useCookie, string baseAddress, string tokenShema, string token) { HttpClient client; if(useCookie) { HttpClientHandler httpClientHandler = new HttpClientHandler(); httpClientHandler.UseCookies = true; httpClientHandler.CookieContainer = new CookieContainer(); client = new HttpClient(httpClientHandler); } else { client = new HttpClient(); } client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); if(!string.IsNullOrWhiteSpace(baseAddress)) { client.BaseAddress = new Uri(baseAddress); } if(!string.IsNullOrWhiteSpace(tokenShema)) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenShema, token); } return client; } #endregion #region 로그인하기 - Login(url, user) /// <summary> /// 로그인하기 /// </summary> /// <param name="url">URL</param> /// <param name="user">사용자</param> /// <returns>JWT 토큰</returns> private static async Task<string> Login(string url, User user) { using(HttpClient client = GetHTTPClient(false, url, null, null)) { var response = await client.PostAsJsonAsync<User>(url, user); if(response.IsSuccessStatusCode) { string token = await response.Content.ReadAsAsync<string>(); return token; } return null; } } #endregion #region 테스트하기 - Test(url, token, test) /// <summary> /// 테스트하기 /// </summary> /// <param name="url">URL</param> /// <param name="token">JWT 토큰</param> /// <param name="test">테스트</param> /// <returns>테스트 결과</returns> private static async Task<IEnumerable<WeatherForecast>> Test(string url, string token) { using(HttpClient client = GetHTTPClient(false, url, "Bearer", token)) { var response = await client.GetAsync(url); if(response.IsSuccessStatusCode) { IEnumerable<WeatherForecast> result = await response.Content.ReadAsAsync<IEnumerable<WeatherForecast>>(); return result; } else // http://로 호출한 경우 https://로 다시 호출한다. { string finalRequestURL = response.RequestMessage.RequestUri.AbsoluteUri; if(finalRequestURL != url) { response = await client.GetAsync(finalRequestURL); if(response.IsSuccessStatusCode) { IEnumerable<WeatherForecast> result = await response.Content.ReadAsAsync<IEnumerable<WeatherForecast>>(); return result; } else { return null; } } else { return null; } } } } #endregion } } |