载荷实体:

/// <summary>
/// JWT载荷实体
/// </summary>
public sealed class JWTPlayloadInfo
{
/// <summary>
/// jwt签发者
/// </summary>
public string iss { get; set; } = "Berry.Service";
/// <summary>
/// jwt所面向的用户
/// </summary>
public string sub { get; set; } = "ALL";
/// <summary>
/// 接收jwt的一方
/// </summary>
public string aud { get; set; } = "guest";
/// <summary>
/// jwt的签发时间
/// </summary>
public string iat { get; set; } = DateTimeHelper.GetTimeStamp(DateTime.Now).ToString();
/// <summary>
/// jwt的过期时间,这个过期时间必须要大于签发时间.默认60分钟
/// </summary>
public string exp { get; set; }
/// <summary>
/// 定义在什么时间之前,该jwt都是不可用的.
/// </summary>
public int nbf { get; set; }
/// <summary>
/// jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
/// </summary>
public string jti { get; set; } = CommonHelper.GetGuid();
/// <summary>
/// 用户ID。自定义字段
/// </summary>
public string userid { get; set; }
/// <summary>
/// 扩展字段。自定义字段
/// </summary>
public string extend { get; set; }
}

JWTHelper.cs:

/// <summary>
/// JWT操作帮助类
/// </summary>
public sealed class JWTHelper
{
/// <summary>
/// 签发Token
/// </summary>
/// <param name="playload">载荷</param>
/// <returns></returns>
public static string GetToken(JWTPlayloadInfo playload)
{
string token = String.Empty; IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
//设置过期时间
DateTime time = DateTime.Now.AddMinutes();
playload.exp = DateTimeHelper.GetTimeStamp(time).ToString();
Dictionary<string, object> dict = playload.Object2Dictionary();
//获取私钥
string secret = GetSecret();
//将Token保存在缓存中
if (!string.IsNullOrEmpty(playload.aud) && playload.aud.Equals("guest"))
{
//计算公用Token
token = CacheFactory.GetCacheInstance().GetCache("JWT_TokenCacheKey:Guest", () =>
{
return encoder.Encode(dict, secret);
}, time);
}
else
{
//计算Token
token = CacheFactory.GetCacheInstance().GetCache($"JWT_TokenCacheKey:{playload.aud}", () =>
{
return encoder.Encode(dict, secret);
}, time);
}
return token;
} /// <summary>
/// Token校验
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public static JWTPlayloadInfo CheckToken(string token)
{
if (string.IsNullOrEmpty(token)) return null; 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); //获取私钥
string secret = GetSecret();
JWTPlayloadInfo playloadInfo = decoder.DecodeToObject<JWTPlayloadInfo>(token, secret, true);
if (playloadInfo != null)
{
if (!string.IsNullOrEmpty(playloadInfo.aud) && playloadInfo.aud.Equals("guest"))
{
string cacheToken = CacheFactory.GetCacheInstance().GetCache<string>("JWT_TokenCacheKey:Guest"); return Check(playloadInfo, cacheToken, token) ? playloadInfo : null;
}
else
{
string cacheToken = CacheFactory.GetCacheInstance().GetCache<string>($"JWT_TokenCacheKey:{playloadInfo.aud}");
return Check(playloadInfo, cacheToken, token) ? playloadInfo : null;
}
}
return null;
} private static bool Check(JWTPlayloadInfo info, string cacheToken, string token)
{
if (string.IsNullOrEmpty(cacheToken)) return false;
if (string.IsNullOrEmpty(token)) return false;
if (!cacheToken.Equals(token)) return false; //Token过期
DateTime exp = DateTimeHelper.GetDateTime(info.exp);
if (DateTime.Now > exp)
{
if (!string.IsNullOrEmpty(info.aud) && info.aud.Equals("guest"))
{
CacheFactory.GetCacheInstance().RemoveCache("JWT_TokenCacheKey:Guest");
}
else
{
CacheFactory.GetCacheInstance().RemoveCache($"JWT_TokenCacheKey:{info.aud}");
}
return false;
}
return true;
} /// <summary>
/// 获取私钥
/// </summary>
/// <returns></returns>
private static string GetSecret()
{
//TODO 从文件中去读真正的私钥
return "eyJpc3MiOiJCZXJyeS5TZXJ2aWNlIiwic3ViIjoiMTgyODQ1OTQ2MTkiLCJhdWQiOiJndWVzdCIsImlhdCI6IjE1MzEzODE5OTgiLCJleHAiOiIxNTMxMzg5MTk4IiwibmJmIjowLCJqdGkiOiI1YzdmN2ZhM2E4ODVlODExYTEzNTQ4ZDIyNGMwMWQwNSIsInVzZXJpZCI6bnVsbCwiZXh0ZW5kIjpudWxsfQ";
}
}

自定义忽略验证特性:

/// <summary>
/// 忽略验证
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class IgnoreTokenAttribute : Attribute
{
public bool Ignore { get; set; }
/// <summary>
/// 忽略验证.默认忽略
/// </summary>
/// <param name="ignore"></param>
public IgnoreTokenAttribute(bool ignore = true)
{
this.Ignore = ignore;
}
}

自定义Action拦截器,处理验证逻辑:

public class CustomActionFilterAttribute : ActionFilterAttribute
{
/// <summary>在调用操作方法之前发生。</summary>
/// <param name="actionContext">操作上下文。</param>
public override void OnActionExecuting(HttpActionContext actionContext)
{
string isInterfaceSignature = ConfigHelper.GetValue("IsInterfaceSignature");
if (isInterfaceSignature.ToLower() == "false") return; BaseJsonResult<string> resultMsg = null;
//授权码
string accessToken = string.Empty;
//操作上下文请求信息
HttpRequestMessage request = actionContext.Request;
//数字签名数据
if (request.Headers.Contains("Authorization"))
{
accessToken = HttpUtility.UrlDecode(request.Headers.GetValues("Authorization").FirstOrDefault());
} //接受客户端预请求
if (actionContext.Request.Method == HttpMethod.Options)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Accepted);
return;
} //忽略不需要授权的方法
var attributes = actionContext.ActionDescriptor.GetCustomAttributes<IgnoreTokenAttribute>();
if (attributes.Count > && attributes[].Ignore) return; //判断请求头是否包含以下参数
if (string.IsNullOrEmpty(accessToken))
{
resultMsg = new BaseJsonResult<string>
{
Status = (int)JsonObjectStatus.ParameterError,
Message = JsonObjectStatus.ParameterError.GetEnumDescription()
};
actionContext.Response = resultMsg.ToHttpResponseMessage();
return;
} //校验Token是否有效
JWTPlayloadInfo playload = JWTHelper.CheckToken(accessToken);
if (playload == null)
{
resultMsg = new BaseJsonResult<string>
{
Status = (int)JsonObjectStatus.TokenInvalid,
Message = JsonObjectStatus.TokenInvalid.GetEnumDescription()
};
actionContext.Response = resultMsg.ToHttpResponseMessage();
return;
}
else
{
//校验当前用户是否能够操作某些特定方法(比如更新用户信息)
if (!attributes[].Ignore)
{
if (!string.IsNullOrEmpty(playload.aud) && playload.aud.Equals("guest"))
{
resultMsg = new BaseJsonResult<string>
{
Status = (int)JsonObjectStatus.Unauthorized,
Message = JsonObjectStatus.Unauthorized.GetEnumDescription()
};
actionContext.Response = resultMsg.ToHttpResponseMessage();
return;
}
}
} base.OnActionExecuting(actionContext);
}
}

在WebApiConfig.cs中注册:

config.Filters.Add(new CustomActionFilterAttribute());

新增获取Token控制器,添加获取Token方法:

/// <summary>
/// 获取授权Token
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
[HttpPost]
[IgnoreToken(true)]
public HttpResponseMessage GetJWTToken(GetTokenArgEntity arg)
{
BaseJsonResult<string> resultMsg = this.GetBaseJsonResult<string>(); Logger(this.GetType(), "获取授权Token-GetJWTToken", () =>
{
if (!string.IsNullOrEmpty(arg.t))
{
//TODO 根据UserID校验用户是否存在
if (true)
{
JWTPlayloadInfo playload = new JWTPlayloadInfo
{
iss = "Berry.Service",
sub = arg.Account,
aud = arg.UserId
};
string token = JWTHelper.GetToken(playload); resultMsg = this.GetBaseJsonResult<string>(token, JsonObjectStatus.Success);
}
else
{
resultMsg = this.GetBaseJsonResult<string>(JsonObjectStatus.UserNotExist);
}
}
else
{
resultMsg = this.GetBaseJsonResult<string>(JsonObjectStatus.Fail, ",请求参数有误。");
}
}, e =>
{
resultMsg = this.GetBaseJsonResult<string>(JsonObjectStatus.Exception, ",异常信息:" + e.Message);
}); return resultMsg.ToHttpResponseMessage();
}

获取Token参数实体:

/// <summary>
/// 获取Token参数
/// </summary>
public class GetTokenArgEntity : BaseParameterEntity
{
/// <summary>
/// 用户ID
/// </summary>
[Required(ErrorMessage = "UserId不能为空")]
public string UserId { get; set; }
/// <summary>
/// 帐号
/// </summary>
[Required(ErrorMessage = "Account不能为空")]
public string Account { get; set; }
}

JWT(JSON Web Tokens)操作帮助类的更多相关文章

  1. Java分布式:JWT(JSON Web Tokens)

    Java分布式:JWT(JSON Web Tokens) 0.优势 Session方式存储用户状态占用大量服务器内存.一般而言,大型应用还需要借助一些KV数据库和一系列缓存机制来实现Session的存 ...

  2. ASP.NET Core 简单集成签发 JWT (JSON Web Tokens)

    什么是 JWT ? 从 https://jwt.io/ 可以了解到对 JWT 的描述:JSON Web Tokens are an open, industry standard RFC 7519 m ...

  3. JWT & JSON Web Tokens

    JSON Web Tokens https://jwt.io json web token example https://jwt.io/introduction/ https://medium.co ...

  4. jwt(JSON Web Tokens)的一道题目代码分析

    题目链接https://github.com/wonderkun/CTF_web/tree/5b08d23ba4086992cbb9f3f4da89a6bb1346b305/web300-6 参考链接 ...

  5. 单点登录-JWT(Json Web Tokens)

    来自:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html 1.跨域认证 1.用户向服务器发送用户名和密码. 2.服务 ...

  6. [翻译]Introduction to JSON Web Tokens

    JWT: Json Web Tokens JWT是一种开放标准(RFC 7519),它定义了一种紧凑且独立的方式,用于将各方之间的信息安全地传输为JSON对象.因为它是经过数字签名的,所以该信息可以进 ...

  7. 服务安全-JWT(JSON Web Tokens):百科

    ylbtech-服务安全-JWT(JSON Web Tokens):百科 JSON Web Tokens是一种开放的行业标准 RFC 7519方法,用于在双方之间安全地表示索赔. JWT.IO允许您解 ...

  8. JSON Web Tokens(JWT)

    现在API越来越流行,如何安全保护这些API? JSON Web Tokens(JWT)能提供基于JSON格式的安全认证.它有以下特点: JWT是跨不同语言的,JWT可以在 .NET, Python, ...

  9. Java JWT: JSON Web Token

    Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...

  10. Go实战--golang中使用JWT(JSON Web Token)

    http://blog.csdn.net/wangshubo1989/article/details/74529333 之前写过关于golang中如何使用cookie的博客: 实战–go中使用cook ...

随机推荐

  1. 把hdfs数据写入到hbase表

    功能:把hdfs上的数据写入到hbase表. hadoop的mapreduce输出要导入到hbase表,最好先输出HFile格式,再导入hbase,因为HFile是hbase的内部存储格式,所以导入效 ...

  2. NetworkX系列教程(6)-对graph进行操作

    小书匠Graph图论 graph生成后,除了有查看操作,还有移除等操作,还有其他更多操作,具体可以看这里.下面将比较graph操作前后的不同. 目录: 7.对图进行操作 7.1移除某些节点和边 7.2 ...

  3. git 忽略文件 目录

    git status 这里面的iml文件类似 eclipse .project文件 ,不能删除 .删除就不能识别项目了. 通过git .gitignore文件 过滤 git status  gitig ...

  4. 【原创】go语言学习(十五)IO操作2

    目录 文件打开和读写 读取压缩文件 bufio原理和cat命令实现 defer详解 文件打开和读写 1. 文件是存储在外部介质上的数据集合. A. 文件分类:文本文件和二进制文件 B. 文件存取方式: ...

  5. 如何在微信小程序中国引入fontawesome字体图标

    fontawesome官网地址:http://fontawesome.dashgame.com/ 一. 二. 下载之后的字体图标 找到 文件中的如下图.ttf文件 三. 在https://transf ...

  6. Linux - /bin/sh^M: bad interpreter: No such file or directory

    问题 在Windows环境下用Notepad++写了个shell脚本,上传到Linux平台后运行报错如下: /bin/sh^M: bad interpreter: No such file or di ...

  7. 三行代码CSS竖向居中

    .element{ position:relative; top:50%; transform:translateY(-50%); } 这里无需设置高度或者父元素的position属性.(IE9可用) ...

  8. LeetCode 第 151 场周赛

    一.查询无效交易(LeetCode-1169) 1.1 题目描述 1.2 解题思路 根据,它和另一个城市中同名的另一笔交易相隔不超过 60 分钟(包含 60 分钟整) 得出 城市A和其他城市任何一笔交 ...

  9. Go 语言入门(三)并发

    写在前面 在学习 Go 语言之前,我自己是有一定的 Java 和 C++ 基础的,这篇文章主要是基于A tour of Go编写的,主要是希望记录一下自己的学习历程,加深自己的理解 Go 语言入门(三 ...

  10. 使用LAS数据集创建DEM和DSM

    作为 LAS 数据集转栅格工具的输入.大多数情况下,此工具的栅格化通过点的快速分组来完成.由于激光雷达相比较于其他采样技术比较密集,所以许多人相信分组已经足够了,不需要更耗时的插值方法.可以证明上述观 ...