开箱即用 - jwt 无状态分布式授权
基于JWT(Json Web Token)的授權方式
JWT 是JSON風格輕量級的授權和身份認證規范,可實現無狀態、分布式的Web應用授權;
從客戶端請求服務器獲取token, 用該token 去訪問實現了jwt認證的web服務器。 token 可保存自定義信息,如用戶基本信息, web服務器用key去解析token,就獲取到請求用戶的信息了;
很方便解決跨域授權的問題,因為跨域無法共享cookie,.net平臺集成的 FormAuthentication 認證系統是基于Session保存授權信息,拿不到cookie就無法認證,用jwt完美解決了。
很多時候,web服務器和授權服務器是同一個項目,所以也可以用以下架構:
實現JWT授權
1.vs2015 新建一個WebApi,安裝下面的庫,可用nuget 或 命令安裝:
install-package Thinktecture.IdentityModel.Core install-package Microsoft.Owin.Security.Jwt2.把Startup.Auth.cs 下的 ConfigureAuth 方法清空掉,改為:
public partial class Startup{ ? ? ? ?public void ConfigureAuth(IAppBuilder app) ? ? ? ?{ ? ? ?
var issuer = ConfigurationManager.AppSettings["issuer"]; ? ? ? ?
? ? ? ?var secret = TextEncodings.Base64Url.Decode(Convert.ToBase64String(
? ? ? ? ?System.Text.Encoding.Default.GetBytes(
? ? ? ? ?ConfigurationManager.AppSettings["secret"]))); ?
? ? ? ? ? ? ? ? ? ?//用jwt進行身份認證app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions{AuthenticationMode = AuthenticationMode.Active,AllowedAudiences = new[] { "Any" },IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
? ? ? ? ? ? ? ? ? ?{ ? ?
? ? ? ? ? ? ? ? ? ?? ?new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)}});app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions{ ? ?
? ? ? ? ? ? ? ? ? ?? ?//生產環境設為falseAllowInsecureHttp = true, ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ?? ? ?//請求token的路徑TokenEndpointPath = new PathString("/oauth2/token"),AccessTokenExpireTimeSpan = TimeSpan.FromDays(30), ? ? ? ? ? ? ? ?//請求獲取token時,驗證username, passwordProvider = new CustomOAuthProvider(), ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ?? ? ?//定義token信息格式 AccessTokenFormat = new CustomJwtFormat(issuer, secret),});}}
3.ConfigureAuth中的 AccessTokenFormat = new CustomJwtFormat(issuer, secret)是自定義token 保存的信息格式, CustomJwtFormat.cs 類代碼
/// <summary> /// 自定義 jwt token 的格式 /// </summary>public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>{ ? ? ? ?private readonly byte[] _secret; ? ? ?private readonly string _issuer; ? ?
public CustomJwtFormat(string issuer, byte[] secret) ?
? ? ?{_issuer = issuer;_secret = secret;} ? ? ?
public string Protect(AuthenticationTicket data) ? ?
? ? { ? ? ? ? ? ?
if (data == null){ ?throw new ArgumentNullException(nameof(data));} ? ? ? ? ?
var signingKey = new HmacSigningCredentials(_secret); ?
var issued = data.Properties.IssuedUtc; ? ?
? ? ? ? ? ?var expires = data.Properties.ExpiresUtc; ? ?
? ? ? ?return new JwtSecurityTokenHandler()
? ? ? ? ?.WriteToken(new JwtSecurityToken(_issuer, "Any", data.Identity.Claims,
? ? ? ? ? issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey));} ? ? ?
? ? ?
? ? ??public AuthenticationTicket Unprotect(string protectedText)
? ? ? ?{ ? ? ? ? ?
? ? ?? ?throw new NotImplementedException();}}
4.ConfigureAuth中的 Provider = new CustomOAuthProvider() 是自定義驗證username, password 的,可以用它來實現訪問數據庫的驗證業務邏輯,CustomOAuthProvider.cs類代碼
? ?/// <summary>/// 自定義 jwt oauth 的授權驗證/// </summary>public class CustomOAuthProvider : OAuthAuthorizationServerProvider{ ? ?? ?? ?public override Task GrantResourceOwnerCredentials(
OAuthGrantResourceOwnerCredentialsContext context) ? ? ?
?{ ? ? ? var username = context.UserName; ? ?
? ?? ??var password = context.Password; ? ?
? ?? ??string userid; ? ? ? ? ?
? ?? ?if (!CheckCredential(username, password, out userid)){context.SetError("invalid_grant", "The user name or password is incorrect");context.Rejected(); ? ? ? ?
? ?? ?? ?return Task.FromResult<object>(null);} ? ? ? ?
? ?? ??? ?var ticket = new AuthenticationTicket(SetClaimsIdentity(context,
? ?? ??? ? userid, username), new AuthenticationProperties());context.Validated(ticket); ? ? ? ? ?
? ?? ?? ?return Task.FromResult<object>(null);} ? ? ?
? ?? ?? ?
? ?? ?public override Task ValidateClientAuthentication(
? ? ? ? ? ? ? ? OAuthValidateClientAuthenticationContext context) ? ? ? ?{context.Validated(); ? ? ? ?
? ?? ?? ?return Task.FromResult<object>(null);} ? ? ?
? ?? ?? ?
? ?? ?? ??private static ClaimsIdentity SetClaimsIdentity(
? ? ?OAuthGrantResourceOwnerCredentialsContext context, string userid, string usercode)
? ? ? ?{ ? ? ? ? ? ?var identity = new ClaimsIdentity("JWT");identity.AddClaim(new Claim("userid", userid));identity.AddClaim(new Claim("username", usercode)); ? ?
? ?? ?? ?? ? ? ? ?return identity;} ? ?
? ?? ?? ?? ? ? ? ?
? ?? ?private static bool CheckCredential(string usernme, string password,
out string userid) ? ? ?
? ? ? ? ??{ ? ? ?
? ?? ?? ? ?var success = false; ? ? ? ? ? ?// 用戶名和密碼驗證if (usernme == "admin" && password == "admin"){userid = "1";success = true;} ? ? ? ? ? ?else{userid = "";} ? ? ? ? ? ?return success;}}
5.Web.config 添加 issue 和 secret
?<appSettings><add key="issuer" value="test"/><!--32個字符的secret--><add key="secret" value="12345678123456781234567812345678"/></appSettings>使用
強烈建議用 chrome 的 postman 插件來調試
獲取token
用token請求數據
header 要添加 Authorization , 值為: Bearer [token], 獲取到的 token 替換 [token], 如
Authorization ? BearereyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiIxIiwidXNlcmNvZG
UiOiIxIiwiaXNzIjoidGVzdCIsImF1ZCI6IkFueSIsImV4cCI6MTQ4NzI0MTQ5MCwibmJmIjo
xNDg0NjQ5NDkwfQ.RaWlJC3OF0RNz4mLtuW4uQtRKDHF8RXwZwzIcbZoNOo
JWT缺點
一旦拿到token, 可用它訪問服務器,直到過期,中間服務器無法控制它,如是它失效(有解決方案: 在 token 中保存信息,可添加額外的驗證,如加一個 flag, 把數據庫對應的flag失效,來控制token有效性)。
token 的過期時間設置很關鍵,一般把它設到凌晨少人訪問時失效,以免用戶使用過程中失效而丟失數據。
token保存的信息有限,且都是字符串。
相關文章:?
.NET Core中的認證管理解析
ASP.NET Core 之 Identity 入門(一)
ASP.NET Core 之 Identity 入門(二)
ASP.NET Core 之 Identity 入門(三)
JWT【JSON Web Token】 簡述
用JWT來保護我們的ASP.NET Core Web API
原文地址:http://www.cnblogs.com/grissom007/p/6294746.html
.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
總結
以上是生活随笔為你收集整理的开箱即用 - jwt 无状态分布式授权的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 异步广度优先搜索算法
- 下一篇: 又踩.NET Core的坑:在同步方法中