问题描述
我正在 ASP.Net Web API 中开发 REST API.我的 API 只能通过非基于浏览器的客户端访问.我需要为我的 API 实现安全性,所以我决定使用基于令牌的身份验证.我对基于令牌的身份验证有一定的了解,并阅读了一些教程,但它们都有一些用于登录的用户界面.我不需要任何用于登录的 UI,因为登录详细信息将由客户端通过 HTTP POST 传递,该 HTTP POST 将从我们的数据库中获得授权.如何在我的 API 中实现基于令牌的身份验证?请注意 - 我的 API 将被高频访问,因此我还必须注意性能.如果我能解释得更好,请告诉我.
I am developing a REST API in ASP.Net Web API. My API will be only accessible via non-browser based clients. I need to implement security for my API so I decided to go with Token based authentication. I have a fair understanding of token based authentication and have read a few tutorials, but they all have some user interface for login. I don't need any UI for login as the login details will be passed by the client through HTTP POST which will be authorized from our database. How can I implement token based authentication in my API? Please note- my API will be accessed in high frequency so I also have to take care of performance.Please let me know if I can explain it any better.
推荐答案
我认为 MVC 和 Web Api 之间的区别有些混淆.简而言之,对于 MVC,您可以使用登录表单并使用 cookie 创建会话.对于 Web Api,没有会话.这就是您要使用令牌的原因.
I think there is some confusion about the difference between MVC and Web Api. In short, for MVC you can use a login form and create a session using cookies. For Web Api there is no session. That's why you want to use the token.
您不需要登录表单.Token 端点就是您所需要的.就像 Win 描述的那样,您会将凭据发送到处理凭据的令牌端点.
You do not need a login form. The Token endpoint is all you need. Like Win described you'll send the credentials to the token endpoint where it is handled.
这是一些用于获取令牌的客户端 C# 代码:
Here's some client side C# code to get a token:
//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;
}
}
为了使用令牌,将其添加到请求的头部:
In order to use the token add it to the header of the request:
//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
In 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 中,实际授予或拒绝访问的代码:
And in ApplicationOAuthProvider.cs the code that actually grants or denies access:
//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);
}
}
如您所见,检索令牌不涉及控制器.事实上,如果您只想要一个 Web Api,您可以删除所有 MVC 引用.我已经简化了服务器端代码以使其更具可读性.您可以添加代码来升级安全性.
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.
确保您仅使用 SSL.实现 RequireHttpsAttribute 以强制执行此操作.
Make sure you use SSL only. Implement the RequireHttpsAttribute to force this.
您可以使用 Authorize/AllowAnonymous 属性来保护您的 Web Api.此外,您可以添加过滤器(如 RequireHttpsAttribute)以使您的 Web Api 更加安全.我希望这会有所帮助.
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.
这篇关于Web API 中基于令牌的身份验证,无需任何用户界面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!