基于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.Coreinstall-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   Bearer 
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiIxIiwidXNlcmNvZG
UiOiIxIiwiaXNzIjoidGVzdCIsImF1ZCI6IkFueSIsImV4cCI6MTQ4NzI0MTQ5MCwibmJmIjo
xNDg0NjQ5NDkwfQ.RaWlJC3OF0RNz4mLtuW4uQtRKDHF8RXwZwzIcbZoNOoJWT缺点
- 一旦拿到token, 可用它访问服务器,直到过期,中间服务器无法控制它,如是它失效(有解决方案: 在 token 中保存信息,可添加额外的验证,如加一个 flag, 把数据库对应的flag失效,来控制token有效性)。 
- token 的过期时间设置很关键,一般把它设到凌晨少人访问时失效,以免用户使用过程中失效而丢失数据。 
- token保存的信息有限,且都是字符串。 
相关文章:
- .NET Core中的认证管理解析 
- ASP.NET Core 之 Identity 入门(三) 
- JWT【JSON Web Token】 简述 
- 用JWT来保护我们的ASP.NET Core Web API 
原文地址:http://www.cnblogs.com/grissom007/p/6294746.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
