사용자 인터페이스없이 Web API의 토큰 기반 인증
ASP.Net Web API에서 REST API를 개발 중입니다. 내 API는 브라우저 기반이 아닌 클라이언트를 통해서만 액세스 할 수 있습니다. API에 대한 보안을 구현해야하므로 토큰 기반 인증을 사용하기로 결정했습니다. 토큰 기반 인증에 대해 공정하게 이해하고 몇 가지 자습서를 읽었지만 모두 로그인을위한 사용자 인터페이스가 있습니다. 로그인 세부 정보는 데이터베이스에서 승인되는 HTTP POST를 통해 클라이언트에 의해 전달되므로 로그인을위한 UI가 필요하지 않습니다. 내 API에서 토큰 기반 인증을 구현하려면 어떻게해야합니까? 내 API는 자주 액세스되므로 성능도 관리해야합니다. 더 잘 설명 할 수 있으면 알려주세요.
MVC와 Web Api의 차이점에 대해 약간의 혼란이 있다고 생각합니다. 간단히 말해서 MVC의 경우 로그인 양식을 사용하고 쿠키를 사용하여 세션을 만들 수 있습니다. Web Api의 경우 세션이 없습니다. 이것이 토큰을 사용하려는 이유입니다.
로그인 양식이 필요하지 않습니다. 토큰 끝점 만 있으면됩니다. Win에서 설명한 것처럼 자격 증명을 처리되는 토큰 끝점으로 보냅니다.
다음은 토큰을 얻기위한 클라이언트 측 C # 코드입니다.
//using System;
//using System.Collections.Generic;
//using System.Net;
//using System.Net.Http;
//string token = GetToken("https://localhost:<port>/", userName, password);
static string GetToken(string url, string userName, string password) {
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>( "grant_type", "password" ),
new KeyValuePair<string, string>( "username", userName ),
new KeyValuePair<string, string> ( "Password", password )
};
var content = new FormUrlEncodedContent(pairs);
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
using (var client = new HttpClient()) {
var response = client.PostAsync(url + "Token", content).Result;
return response.Content.ReadAsStringAsync().Result;
}
}
토큰을 사용하려면 요청 헤더에 추가하십시오.
//using System;
//using System.Collections.Generic;
//using System.Net;
//using System.Net.Http;
//var result = CallApi("https://localhost:<port>/something", token);
static string CallApi(string url, string token) {
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
using (var client = new HttpClient()) {
if (!string.IsNullOrWhiteSpace(token)) {
var t = JsonConvert.DeserializeObject<Token>(token);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + t.access_token);
}
var response = client.GetAsync(url).Result;
return response.Content.ReadAsStringAsync().Result;
}
}
토큰은 다음과 같습니다.
//using Newtonsoft.Json;
class Token
{
public string access_token { get; set; }
public string token_type { get; set; }
public int expires_in { get; set; }
public string userName { get; set; }
[JsonProperty(".issued")]
public string issued { get; set; }
[JsonProperty(".expires")]
public string expires { get; set; }
}
이제 서버 측 :
Startup.Auth.cs에서
var oAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider("self"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// https
AllowInsecureHttp = false
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(oAuthOptions);
그리고 ApplicationOAuthProvider.cs에서 실제로 액세스를 허용하거나 거부하는 코드는 다음과 같습니다.
//using Microsoft.AspNet.Identity.Owin;
//using Microsoft.Owin.Security;
//using Microsoft.Owin.Security.OAuth;
//using System;
//using System.Collections.Generic;
//using System.Security.Claims;
//using System.Threading.Tasks;
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
throw new ArgumentNullException("publicClientId");
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager);
var propertyDictionary = new Dictionary<string, string> { { "userName", user.UserName } };
var properties = new AuthenticationProperties(propertyDictionary);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
// Token is validated.
context.Validated(ticket);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
context.Validated();
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
var expectedRootUri = new Uri(context.Request.Uri, "/");
if (expectedRootUri.AbsoluteUri == context.RedirectUri)
context.Validated();
}
return Task.FromResult<object>(null);
}
}
As you can see there is no controller involved in retrieving the token. In fact, you can remove all MVC references if you want a Web Api only. I have simplified the server side code to make it more readable. You can add code to upgrade the security.
Make sure you use SSL only. Implement the RequireHttpsAttribute to force this.
You can use the Authorize / AllowAnonymous attributes to secure your Web Api. Additionally you can add filters (like RequireHttpsAttribute) to make your Web Api more secure. I hope this helps.
ASP.Net Web API has Authorization Server build-in already. You can see it inside Startup.cs when you create a new ASP.Net Web Application with Web API template.
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
All you have to do is to post URL encoded username and password inside query string.
/Token/userName=johndoe%40example.com&password=1234&grant_type=password
If you want to know more detail, you can watch User Registration and Login - Angular Front to Back with Web API by Deborah Kurata.
'IT TIP' 카테고리의 다른 글
| Tomcat과 TomEE, TomEE 및 TomEE Plus의 차이점은 무엇입니까? (0) | 2020.11.24 |
|---|---|
| Angular2 : 자식 구성 요소 액세스 부모 클래스 변수 / 함수 (0) | 2020.11.24 |
| Git : 이전 커밋에서 파일을 체크 아웃하고 HEAD로 수정 (0) | 2020.11.24 |
| 정적 const float가 허용되지 않는 이유는 무엇입니까? (0) | 2020.11.23 |
| 이니셜 라이저 오류의 예외 (0) | 2020.11.23 |