前言:采用Client Credentials方式,即密钥key/password,场景通常是分为客户端限制必须有权限才能使用的模块,这和微信公众号开放平台很相似。html
让用户经过客户端去获取本身的token,在根据这个token去获取资源。jquery
使用WebApi基于Microsoft.Owin.Security.OAuth实现,新建一个空为WebApi项目。ajax
using Microsoft.Owin.Security; using Microsoft.Owin.Security.OAuth; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using System.Web; namespace ApiThrottleDemo { public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider { /// <summary> /// 验证客户[client_id与client_secret验证] /// </summary> public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { //http://localhost:48339/token string client_id; string client_secret; context.TryGetFormCredentials(out client_id, out client_secret); if (client_id == "zara" && client_secret == "123456") { context.Validated(client_id); } else { //context.Response.StatusCode = Convert.ToInt32(HttpStatusCode.OK); context.SetError("invalid_client", "client is not valid"); } return base.ValidateClientAuthentication(context); } /// <summary> /// 客户端受权[生成access token] /// </summary> public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context) { var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType); oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, "iphone")); var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties() { AllowRefresh = true }); context.Validated(ticket); return base.GrantClientCredentials(context); } /// <summary> /// 刷新Token[刷新refresh_token] /// </summary> public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context) { //enforce client binding of refresh token if (context.Ticket == null || context.Ticket.Identity == null || !context.Ticket.Identity.IsAuthenticated) { context.SetError("invalid_grant", "Refresh token is not valid"); } return base.GrantRefreshToken(context); } } }
在此其中呢,须要继承OAuthAuthorizationServerProvider,并重写本身想重写的方法,其内部定义下图所示:api
固然这还没完,咱们还须要去配置应用程序。在Startup.cs,咱们要开启BearerToken认证模式;该Provider
属性指定了一个插入OWIN中间件的提供程序,并处理由中间件引起的事件。安全
如下是应用想要获取令牌时的基本流程:服务器
要获取访问令牌,应用程序会向〜/ Token发送请求。
OAuth中间件调用GrantResourceOwnerCredentials提供程序。
提供程序调用ApplicationUserManager以验证凭据并建立声明标识。
若是成功,则提供程序会建立一个身份验证票证,用于生成令牌。微信
app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/token"), Provider = new ApplicationOAuthProvider(), AccessTokenExpireTimeSpan = TimeSpan.FromHours(2), AuthenticationMode = AuthenticationMode.Active, AllowInsecureHttp = true });
其中AccessTokenExpireTimeSpan参数是token过时时间,AllowInsecureHttp 是否开启安全验证,TokenEndpointPath就是你获取token对于服务器的相对路径,那咱们都知道用户只能访问咱们的Api,那如何在api上去走Oauth呢?app
在控制器种建立一个控制器,命名为:OAuth2Controller。iphone
[RoutePrefix("api/v1/oauth2")] public class OAuth2Controller : ApiController { [Authorize] [Route("news")] public async Task<IHttpActionResult> GetNewsAsync() { var authentication = HttpContext.Current.GetOwinContext().Authentication; var ticket = authentication.AuthenticateAsync("Bearer").Result; var claimsIdentity = User.Identity as ClaimsIdentity; var data = claimsIdentity.Claims.Where(c => c.Type == "urn:oauth:scope").ToList(); var claims = ((ClaimsIdentity)Thread.CurrentPrincipal.Identity).Claims; return Ok(new { IsError = true, Msg = string.Empty, Data = Thread.CurrentPrincipal.Identity.Name + " It's about news !!! token expires: " + ticket.Properties.Dictionary.ToString() }); } }
启用受权验证[WebApiConfig]async
在ASP.NET Web API中启用Token验证,须要加上[Authorize]标记,而且配置默认启用验证不记名受权方式
config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
服务端[/token]获取token须要三个参数,咱们使用你们熟悉的PostMan去试一试吧,启动项目。
那咱们不难看到,已经成功获取了access_token,至于这个token的值,只要你的client_id不一样它就必定是不会相同的(实在不行你能够搞个GUID),那么咱们再构建一个ajax去模拟的获取token吧。
作个简单的页面:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script> </head> <body> <input type="text" placeholder="client_id"/><br /> <input type="text" placeholder="client_secret"/><br /> <input type="text" placeholder="your_token"/><br /> <button>获取token</button> </body> <script> $(function () { $("button").click(function () { $.ajax({ url: "http://localhost:58560/token", type: "post", data: "grant_type=client_credentials&client_id=zara&client_secret=123456", success: function (res) { console.log(res); } }) }) }) </script> </html>
这是生成的token。
最后总结,你能够在ValidateClientAuthentication中进行身份判断,若是有这个身份,那么我就存储DB中,这样的话,相似于一个微信身份受权的功能基本上就是这样了。