一.项目需求:
1.调用外部接口链接,需要使用JWT获取token。
(本次案例使用JWT10.0,底层调用了Newtonsoft.Json13.0的方法)
二.项目难点:
1.金蝶云星空自带的Newtonsoft.Json 4.0版本过低,不能支持JWT所需的Newtonsoft.Json 13.0方法。
三.解决方案:
解释:替换金蝶自带的Newtonsoft.Json是不可能的,金蝶云星空底层的框架是调用了Newtonsoft.Json的方法的,直接替换会导致整个系统无法运行
1.思路:
a.反编译JWT 10.0,Newtonsoft.Json 13.0。
b. 在低版本Newtonsoft.Json的基础上,重写高版本Newtonsoft.Json的方法。
(本次案例是在Newtonsoft.Json4.0的基础上,实现Newtonsoft.Json13.0的部分方法,从而实现JWT获取token)
c.步骤就是visual studio哪里报错,在反编译工具中找到报错的属性或方法,添加到自定义类中
2.使用工具:Visual Studio(开发工具),ILSpy(反编译工具)
3.操作步骤:
a.新增自定义类JsonNetSerializer
b.新增自定义静态类ExpandMethod,里面写支持JsonNetSerializer的属性,方法
c.在Visual Studio 中报错的方法或者属性,在ILSpy工具中找到并粘贴到自定义方法中
d.调试运行,方案通过
4.代码如下:
在Newtonsoft.Json 13.0的条件下,调用JWT获取token。
代码块1:
//返货Token信息
public static string JWTEncode(string ucode)
{
var secretKey = AppSettingService.SecretKey;//获取jwt密钥,示例是存放到配置文件
if (!String.IsNullOrEmpty(secretKey))
{
var dic = new Dictionary<string, object>();
dic["systemName"] = ucode;//增加用户名到字典
var expiredTimeSpan = 1;
if (!String.IsNullOrEmpty(AppSettingService.ExpiredTimeSpan))
{
var timeSpan = AppSettingService.ExpiredTimeSpan;
if (System.Text.RegularExpressions.Regex.IsMatch(timeSpan, "^[1-9]\\d*$"))
{
expiredTimeSpan = Convert.ToInt32(timeSpan);
}
}
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddMinutes(expiredTimeSpan) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);
dic["exp"] = jwtcreatedOver;// 指定token的生命周期。unix时间戳格式
IJwtAlgorithm algorithm = new HMACSHA512Algorithm();
IJsonSerializer serializer = new JsonNetSerializer(); //在Newtonsoft.Json 4.0的条件下,这个方法报错
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder.Encode(dic, secretKey);//返回生成的token
}
else
return "";
}
在Newtonsoft.Json 4.0的条件下,重写上面案例的JsonNetSerializer方法,调用JWT获取token。
代码块2:
1.自定义静态JsonNetSerializer类:(直接从ILSpy反编译工具中整段复制出来)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace ZJYceshi
{
//继承JWT.IJsonSerializer,后面才能进行类型转换
public class JsonNetSerializer:JWT.IJsonSerializer
{
private readonly JsonSerializer _serializer;
//ExpandMethod.CreateDefault()为自定义方法,原方法为JsonSerializer.CreateDefault(),属于Newtonsoft.Json 13.0的方法
public JsonNetSerializer() : this(ExpandMethod.CreateDefault())
{
}
public JsonNetSerializer(JsonSerializer serializer)
{
if (serializer == null)
{
throw new ArgumentNullException("serializer");
}
this._serializer = serializer;
}
public string Serialize(object obj)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
StringBuilder stringBuilder = new StringBuilder();
string result;
using (StringWriter stringWriter = new StringWriter(stringBuilder))
{
using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter))
{
this._serializer.Serialize(jsonTextWriter, obj);
result = stringBuilder.ToString();
}
}
return result;
}
public object Deserialize(Type type, string json)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (string.IsNullOrEmpty(json))
{
throw new ArgumentException("json");
}
object result;
using (StringReader stringReader = new StringReader(json))
{
using (JsonTextReader jsonTextReader = new JsonTextReader(stringReader))
{
result = this._serializer.Deserialize(jsonTextReader, type);
}
}
return result;
}
}
}
2.自定义静态ExpandMethod,将程序所需的Newtonsoft.Json 13.0的方法添加到此类中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace ZJYceshi
{
public static class ExpandMethod
{
public static JsonSerializer CreateDefault()
{
Func<JsonSerializerSettings> expr_05 = ExpandMethod.DefaultSettings;
return JsonSerializer.Create((expr_05 != null) ? expr_05() : null);
}
[Nullable(new byte[]
{
2,
1
})]
public static Func<JsonSerializerSettings> DefaultSettings
{
[return: Nullable(new byte[]
{
2,
1
})]
get;
[param: Nullable(new byte[]
{
2,
1
})]
set;
}
[Embedded, AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false), CompilerGenerated]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte b)
{
this.NullableFlags = new byte[]
{
b
};
}
public NullableAttribute(byte[] nullableFlags)
{
this.NullableFlags = nullableFlags;
}
}
[Embedded, CompilerGenerated]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
}
3.微调JWT获取Token方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Newtonsoft.Json;
namespace ZJYceshi
{
public class ResultToken
{
public static string JWTEncode(string ucode)
{
var secretKey = AppSettingService.SecretKey;//获取jwt密钥,示例是存放到配置文件
if (!String.IsNullOrEmpty(secretKey))
{
var dic = new Dictionary<string, object>();
dic["systemName"] = ucode;//增加用户名到字典
var expiredTimeSpan = 1;
if (!String.IsNullOrEmpty(AppSettingService.ExpiredTimeSpan))
{
var timeSpan = AppSettingService.ExpiredTimeSpan;
if (System.Text.RegularExpressions.Regex.IsMatch(timeSpan, "^[1-9]\\d*$"))
{
expiredTimeSpan = Convert.ToInt32(timeSpan);
}
}
var jwtcreatedOver =
Math.Round((DateTime.UtcNow.AddMinutes(expiredTimeSpan) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds + 5);
dic["exp"] = jwtcreatedOver;// 指定token的生命周期。unix时间戳格式
IJwtAlgorithm algorithm = new HMACSHA512Algorithm();
//JsonSerializer serializer = new JsonNetSerializer();
//调整语句,将紫定义JsonNetSerializer类,强制转换为JWT10.0的类
IJsonSerializer serializer = (IJsonSerializer)(new JsonNetSerializer());
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder.Encode(dic, secretKey);//返回生成的token
}
else
return "";
}
}
}
5.方案结果:
1.Newtonsoft.Json 13.0 和 Newtonsoft.Json 4.0 环境下,JWT获取tokn均成功!