一.项目需求:
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}elsereturn "";}
在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}elsereturn "";}}
}
5.方案结果:
1.Newtonsoft.Json 13.0 和 Newtonsoft.Json 4.0 环境下,JWT获取tokn均成功!