载荷实体:

/// <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. Python基础之只接收关键字参数的函数

    当我们希望函数的某些参数强制使用关键字参数时,可以将强制关键字参数放到某个*后面就能得到这种效果.比如: def recv(maxsize, *, block): """ ...

  2. 3、Web server 之httpd2.2 配置说明

    http协议实现的程序 静态(httpd, nginx, lighttpd) 动态 (IIS, tomcat,  jetty,  jboss,  resin,  websphere, weblogic ...

  3. C# 图片进行马赛克处理

    MosaicHelper.AdjustTobMosaic( @"C:\Users\xxxue\Desktop\QQ图片20180704142029.jpg", @"C:\ ...

  4. springboot开启gzip压缩

    springboot 2.x开启gzip压缩 1.application.yml配置 server: compression: enabled: true min-response-size: mim ...

  5. ansible 主机正则

    ansible <pattern> -m <module_name> -a <arguments> 该功能主要针对Inventory的主机列表,案例如下: 1.AL ...

  6. zabbix(12)使用Grafana

    一.Grafana介绍 Grafana是一个跨平台的开源的度量分析和可视化工具,可以通过将采集的数据查询然后可视化的展示,并及时通知.它主要有以下六大特点: 1.展示方式:快速灵活的客户端图表,面板插 ...

  7. Linux下 为什么有时候使用sudo也提示没有权限

    例如: #sudo echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6 bash: /proc/sys/net/ipv6/conf/all/dis ...

  8. LeetCode 第 150 场周赛

    一.拼写单词(LeetCode-1160) 1.1 题目描述 1.2 解题思路 由于给定的chars,每个字母只能用一次,所以用大小为26的数组charsArray来表示a-z(例如charsArra ...

  9. SpringCloud介绍及入门(二)

    接口的实现 在user_service_interface中添加一个User的类. 增加私有属性 id,name , 并利用快捷键Alt+Insert 实现get,set的快速生成. 实体类User ...

  10. Spring框架中不同类型的事件

    ContextRefreshedEvent,ApplicationContext初始化或者被更新是会触发,ConfigurableApplicationContext接口中的refresh()方法被调 ...