是 JSON 风格轻量级的授权和身份认证规范,可实现无状态、分布式的 Web 应用授权;
从客户端请求服务器获取 token, 用该 token 去访问实现了 jwt 认证的 web 服务器。 token 可保存自定义信息,如用户基本信息, web 服务器用 key 去解析 token,就获取到请求用户的信息了;
很方便解决跨域授权的问题,因为跨域无法共享 cookie,.net 平台集成的 FormAuthentication 认证系统是基于 Session 保存授权信息,拿不到 cookie 就无法认证,用 jwt 完美解决了。
很多时候,web 服务器和授权服务器是同一个项目,所以也可以用以下架构:
1.vs2015 新建一个 WebApi, 安装下面的库,可用 nuget 或 命令安装:
- install-package Thinktecture.IdentityModel.Core
- install-package Microsoft.Owin.Security.Jwt
2. 把 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
- {
- //生产环境设为false
- AllowInsecureHttp = true,
- //请求token的路径
- TokenEndpointPath = new PathString("/oauth2/token"),
- AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),
- //请求获取token时,验证username, password
- Provider = 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 插件来调试
header 要添加 Authorization , 值为: Bearer [token], 获取到的 token 替换 [token], 如
- Authorization Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiIxIiwidXNlcmNvZGUiOiIxIiwiaXNzIjoidGVzdCIsImF1ZCI6IkFueSIsImV4cCI6MTQ4NzI0MTQ5MCwibmJmIjoxNDg0NjQ5NDkwfQ.RaWlJC3OF0RNz4mLtuW4uQtRKDHF8RXwZwzIcbZoNOo
来源: