- 什么是JWT
Json web Token是一个开放的标准,这个标准允许我们使用jwt在用户和服务器之间传递安全可靠的信息。
- jwt的组成
结构:头部(Header)、载荷(payload)、签名(signature)
1.头部(Header)
{
"typ": "JWT",
"alg": "HS256"
}
这里声明类型和加密算法,要进行Base64编码得到的编码是jwt的Header
2.载荷(payload)
{
"iss": "John Wu JWT",
"iat": 1441593502,
"exp": 1441594722,
"aud": "www.example.com",
"sub": "jrocket@example.com",
}
这里面的前五个字段都是由JWT的标准所定义的。
- iss: 该JWT的签发者
- sub: 该JWT所面向的用户
- aud: 接收该JWT的一方
- exp(expires): 什么时候过期,这里是一个Unix时间戳
- iat(issued at): 在什么时候签发的
将该json对象进行base64编码得到的字符串就是jwt的Payload(载荷)
- 签名(signature)
将Header和Payload编码后的字符串都用句号.连在一起(头部在前面)得到的字符串,用
HS256算法进行加密。加密的时候提供一个密钥(secret).
这一部分又叫做签名。
最后将这一部分签名也拼接在被签名的字符串后面,我们就得到完整的jwt.
3.jwt适用的场景
加好友的操作、下订单的操作、设计用户认证和授权系统、web应用的单点登录
- web api使用jwt认证
1.建立一个web api项目
2.项目右键-管理Nuget程序包—找到jwt,安装
3.Model文件夹下新建三个类LoginResult,LoginRequest,AuthInfo
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication13.Models
{
public class LoginResult
{
public bool Success { get; set; }
public string Token { get; set; }
public string Message { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication13.Models
{
public class LoginRequest
{
public string UserName { get; set; }
public string Password { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication13.Models
{
public class AuthInfo
{
//模拟JWT的payload
public string UserName { get; set; }
public List<string> Roles { get; set; }
public bool IsAdmin { get; set; }
}
}
4.在controller文件夹中的HomeController中添加一个Post方法,这是生成JWT Token方法的地方。
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
using WebApplication13.Models;
namespace WebApplication13.Controllers
{
[EnableCors(origins: "http://localhost:62815", headers: "*", methods: "GET,POST,PUT,DELETE")]
public class HomeController : ApiController
{
public LoginResult Post([FromBody]LoginRequest request)
{
LoginResult rs = new LoginResult();
//这是是获取用户名和密码的,这里只是为了模拟
if (request.UserName == "kfz" && request.Password == "123456")
{
AuthInfo info = new AuthInfo { UserName = "kfz", Roles = new List<string> { "Admin", "Manage" }, IsAdmin = true };
try
{
const string secret = "To Live is to change the world";
//secret需要加密
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var token = encoder.Encode(info, secret);
rs.Message = "XXXXX";
rs.Token = token;
rs.Success = true;
}
catch (Exception ex)
{
rs.Message = ex.Message;
rs.Success = false;
}
}
else
{
rs.Message = "fail";
rs.Success = false;
}
return rs;
}
}
}
- 项目中添加一个Attributes文件夹,写一个权限拦截器,新建一个ApiAuthorizeAttribute类继承自AuthorizeAttribute类
using JWT;
using JWT.Serializers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using WebApplication13.Models;
namespace WebApplication13.Attributes
{
public class ApiAuthorizeAttribute: AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
var authHeader = from t in actionContext.Request.Headers where t.Key == "auth" select t.Value.FirstOrDefault();
if (authHeader != null)
{
string token = authHeader.FirstOrDefault();
if (!string.IsNullOrEmpty(token))
{
try
{
const string secret = "To Live is to change the world";
//secret需要加密
IJsonSerializer serializer = new JsonNetSerializer();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
var json = decoder.DecodeToObject<AuthInfo>(token, secret, verify: true);
if (json != null)
{
actionContext.RequestContext.RouteData.Values.Add("auth", json);
return true;
}
return false;
}
catch (Exception ex)
{
return false;
}
}
}
return false;
}
}
}
- controller文件夹中新建一个UserController,新建一个Get的Action,需要加上ApiAuthorize特性
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
using WebApplication13.Attributes;
using WebApplication13.Models;
namespace WebApplication13.Controllers
{
[EnableCors(origins: "http://localhost:62815", headers: "*", methods: "GET,POST,PUT,DELETE")]
public class UserController : ApiController
{
// GET: User
[ApiAuthorize]
public string Get()
{
AuthInfo info = RequestContext.RouteData.Values["auth"] as AuthInfo;
if (info == null)
{
return "获取不到,失败";
}
else
{
return $"获取到了,Auth的Name是 {info.UserName}";
}
}
}
}
- 对于跨域问题可以参考之前的web api的文章,这里我使用的是特性
[EnableCors(origins: "http://localhost:62815", headers: "*", methods: "GET,POST,PUT,DELETE")]
- 部署web api到服务器上,然后用另一个跨域的页面调用接口访问
@{
ViewBag.Title = "Test";
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<meta charset="utf-8" />
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
</head>
<body>
<fieldset>
<legend>身份验证</legend>
<form>
<label for="UserName">用户名:</label><input type="text" name="userName" id="userName" value="admin" />
<br />
<br />
<label for="Password">密码:</label><input type="password" name="password" id="password" value="123" />
<br />
<br />
</form>
<button id="login">登录</button>
</fieldset>
<br />
<fieldset>
<legend>调用接口</legend>
<button id="invoke">调用接口</button>
</fieldset>
<script>
$(function () {
//调用api站点的登录接口,接口在登录成功后返回一个token。
$("#login").on("click", function () {
$.ajax({
url: "http://localhost:55221/api/home",
data: $("form").serialize(),
method: "post",
success: function (data) {
if (data.Success) {
//为简单起见,将token保存在全局变量中。
window.token = data.Token;
alert("登录成功");
} else {
alert("登录失败:" + data.Message);
}
}
});
});
//调用api站点的获取数据的接口,该接口要求身份验证。
$("#invoke").on("click", function () {
console.log(window.token);
$.ajax({
url: "http://localhost:55221/api/user",
method: "get",
headers: { "auth": window.token },//通过请求头来发送token,放弃了通过cookie的发送方式
complete: function (jqXHR,textStatus) {
alert(jqXHR.responseText);
},
});
});
});
</script>
</body>
</html>
本文参考链接:
https://www.cnblogs.com/lwhkdash/p/6686999.html
https://www.cnblogs.com/wangyulong/p/8727683.html