WebApi JWT 身份验证 Net 使用JWT

.Net 使用JWT

JWT

  • 什么是JSON Web Token?

SON Web Token(以下简称 JWT)是一套开放的标准(RFC 7519),它定义了一套简洁(compact)且 URL 安全(URL-safe)的方案,以安全地在客户端和服务器之间传输 JSON 格式的信息。

  • 它有什么优点?
  • 体积小(一串字符串)。因而传输速度快
  • 传输方式多样。可以通过 HTTP 头部(推荐)/URL/POST 参数等方式传输
  • 严谨的结构化。它自身(在 payload 中)就包含了所有与用户相关的验证消息,如用户可访问路由、访问有效期等信息,服务器无需再去连接数据库验证信息的有效性,并且 payload 支持应用定制
  • 支持跨域验证,多应用于单点登录
  • 为什么使用JWT?

充分依赖无状态 API ,契合 RESTful 设计原则(无状态的 HTTP)

JWT的Token组成部分

  • header:对token的类型以及加密方法进行base64加密得到;
  • payload:对有效信息进行base64加密得到;
  • signature:对base64加密后的header和base64加密后的payload使用’.’组合为字符串,再通过header中指定的加密方式加secret组合加密;

他是怎么鉴别客户端传来的tojen是否被篡改的?

在我们收到客户端的token后,将token的第一和第二部分,再次进行组合加密第三部分的过程,得到一个signature。如果这个singature和token里的singnature对比不同,则token被篡改。
因此我们服务器端必须保留secret且不能泄露,否则客户端可以自行签发。

如何使用JWT

  • 加密
    • 引入JWT程序包
  • 生成token
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
c#复制代码    private static string Secret = "serect";
static void Main(string[] args)
{
//如果设定过期时间,一定的是秒数
var payload = new Dictionary<string, object>() {
{"name","huangwei" },
};
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlencoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlencoder);
var token = encoder.Encode(payload, Secret);
Console.WriteLine(token);
Console.ReadKey();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
c#复制代码    private static string Secret = "serect";
static void Main(string[] args)
{
IDateTimeProvider provider = new UtcDateTimeProvider();
var timeSpan=provider.GetNow().AddHours(1).ToUnixTimeSeconds();
var payload = new Dictionary<string, object>() {
{"name","huangwei" },
{"exp",timeSpan},
};
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlencoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlencoder);
var token = encoder.Encode(payload, Secret);
Console.WriteLine(token);
Console.ReadKey();
}
}

WebApi中使用JWT进行身份验证

  • 发起登录请求,并传递参数
  • 接收参数,验证登录逻辑,登陆成功则返回token
  • 客户端接受,保存token,请求权限api,并将token附加在header头
  • 服务器验证身份,如果token不存在或token被篡改,验证失败,没有权限获得数据
  • 未使用过滤器的身份验证,略显代码冗余
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
c#复制代码    public class JwtTools
{
//密钥,
public static string key = "love this world and love you too";
public static string Encode(Dictionary<string,object> payload,long expTime,string key)
{
key = key == null ? key : JwtTools.key;
payload.Add("exp", expTime);
IJsonSerializer serializer = new JsonNetSerializer();
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IBase64UrlEncoder base64UrlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, base64UrlEncoder);
//通过header.payload 用 key加密 生成第三段 signature 并返回三段完整token
var token = encoder.Encode(payload, key);
return token;
}
private static string DeEncode(string token,string key)
{
try
{
key = key == null ? key : JwtTools.key;
IJsonSerializer jsonSerializer = new JsonNetSerializer();
var provider = new UtcDateTimeProvider();
IJwtValidator jwtValidator = new JwtValidator(jsonSerializer, provider);
IBase64UrlEncoder base64UrlEncoder = new JwtBase64UrlEncoder();
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJwtDecoder decoder = new JwtDecoder(jsonSerializer,jwtValidator,base64UrlEncoder,algorithm);
var json = decoder.Decode(token, key,verify:true);
return json;
}
catch (TokenExpiredException)
{
throw;
}
catch (SignatureVerificationException)
{
throw;
}
}
public static string ValidateLogin(HttpRequestHeaders headers, string key)
{
if (headers.GetValues("token") == null || !headers.GetValues("token").Any())
{
throw new Exception("请登录");
}
return DeEncode(headers.GetValues("token").First(), key);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c#复制代码        [HttpPost]
[Route("Login")]
public string Login(dynamic model)
{
if(model.userName.ToString().Length>2 && model.userPwd.ToString() == "123456")
{
return JwtTools.Encode(new Dictionary<string, object>(){
{"name",model.userName.ToString() }
},DateTimeOffset.UtcNow.AddMinutes(30).ToUnixTimeSeconds(),JwtTools.key);
}
throw new Exception("登录失败");
}
[HttpGet]
[Route("getMs")]
public string GetAccoutMS()
{
var json = JwtTools.ValidateLogin(Request.Headers, JwtTools.key);
//首先我们要知道webApi中 http无状态
return json;
}
}

使用这种方法可以实现身份验证,但是如果每个Action都需要通过身份验证,我们岂不是需要在每一个Action中都写一次调用。显然很麻烦。

因此我们有第二种方法,过滤器,当每一次请求到达时,都将先执行过滤器的方法,如果通过则将执行Action。符合asp.net管道事件。

  • 过滤器
    • 1.使用过滤器对JWT进行验证
    • 2.将验证过后得到的结果赋给User.Identity……
    • 3.因为User和Identity是接口类型,因此我们可以实现这些接口,并在过滤器中赋值给User和Identity

      过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
c#复制代码public class MyAuth : Attribute, IAuthorizationFilter
{
public bool AllowMultiple { get; }

public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
IEnumerable<string> headers;
if(actionContext.Request.Headers.GetValues("token")==null|| actionContext.Request.Headers.TryGetValues("token",out headers) == false)
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
var logName = JwtTools.DeEncode<Dictionary<string,object>>(headers.First())["user"];
var userID = JwtTools.DeEncode<Dictionary<string,object>>(headers.First())["userID"];
//过期时间
var expTime = (long)JwtTools.DeEncode<Dictionary<string, object>>(headers.First())["exp"];
if(DateTimeOffset.UtcNow.ToUnixTimeSeconds() > expTime)
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
(actionContext.ControllerContext.Controller as ApiController).User = new AppUser(logName.ToString(), int.Parse(userID.ToString()));
return await continuation();
}
}

实现User和Identity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
c#复制代码public class AppUser : IPrincipal
{
public AppUser(string name,int id)
{
Identity = new AppIdentity(name, id);
}
public IIdentity Identity { get; }

public bool IsInRole(string role)
{
throw new NotImplementedException();
}
}
public class AppIdentity : IIdentity
{
public AppIdentity(string name,int id)
{
Name= name;
Id = id;
}
public string Name { get; }
public int Id { get;}

public string AuthenticationType { get; }

public bool IsAuthenticated { get; }
}

JWTTools

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
c#复制代码public class JwtTools
{
public static string key = "huangwei@";
public static string Encode(Dictionary<string,object> payload,string key=null)
{
key = string.IsNullOrEmpty(key) ? JwtTools.key : key;
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder base64UrlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, base64UrlEncoder);
payload.Add("exp",DateTimeOffset.UtcNow.AddHours(2).ToUnixTimeSeconds());
var json=encoder.Encode(payload, key);
return json;
}
public static T DeEncode<T>(string token, string key = null)
{
key = string.IsNullOrEmpty(key) ? JwtTools.key : key;
try
{
var provider = new UtcDateTimeProvider();
IJsonSerializer jsonSerializer = new JsonNetSerializer();
IBase64UrlEncoder base64UrlEncoder = new JwtBase64UrlEncoder();
IJwtValidator validator = new JwtValidator(jsonSerializer, provider);
IJwtAlgorithm jwtAlgorithm = new HMACSHA256Algorithm();
IJwtDecoder decoder = new JwtDecoder(jsonSerializer, validator, base64UrlEncoder, jwtAlgorithm);
var json = decoder.Decode(token, key, verify: true);
return JsonConvert.DeserializeObject<T>(json);
}
catch (TokenExpiredException)
{
throw;
}
catch (SignatureVerificationException)
{
throw;
}
}
}
  • WebApi支持数据注解

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%