具体的授权认证在微信小程序的官方文档,偷个懒,就不写了
推荐一个好用的http请求类库
$ install-package Flurl
$ install-package Flurl.Http
- 链式的http请求方式,可以说比前端的axios.js更好用
- 入门基础可以百度到的,就不过多介绍了
定义一个微信小程序Exception
public class WeixinMiniProgramExcption:Exception
{
public WeixinMiniProgramExcption(string message):base(message)
{
}
//props...
}
定义一个文件配置实体类
public class WeixinMiniProgramOptions:IOptions<WeixinMiniProgramOptions>
{
public string AppId { get; set; } //小程序的AppId
public string AppSecret { get; set; } //小程序的AppSecret
public WeixinMiniProgramOptions Value => this;
}
定义一个小程序用户实体类 接下来会用到
public class WeixinUserInfo
{
public string OpenId { get; set; }
[JsonProperty("session_key")]
public string SessionKey { get; set; }
public string UnionId { get; set; }
public int ErrCode { get; set; }
public string ErrMsg { get; set; }
}
服务类 ,直接开搞,请看注释
public class WeixinMiniProgramOAuthService
{
//使用控制反转的方式
private readonly WeixinMiniProgramOptions _options;
//一开始说的Flurl 客户端,在构造函数初始化,规范点
private readonly IFlurlClient _client;
public WeixinMiniProgramOAuthService(IOptions<WeixinMiniProgramOptions> options)
{
_options = options.Value;
//使用 baseUrl 这个构造函数
_client = new FlurlClient("https://api.weixin.qq.com");
}
public async Task<WeixinUserInfo> AuthorizationCodeAsync(string code)
{
//这就是Flurl的好用之处
var data = await _client.Request("/sns/jscode2session")
.SetQueryParam("appid", _options.AppId)
.SetQueryParam("secret", _options.AppSecret)
.SetQueryParam("js_code", code)
.SetQueryParam("grant_type", "authorization_code")
.GetJsonAsync<WeixinUserInfo>();
//抛异常的好处是快速定位到bug,方便后续扩展操作
if (data.ErrCode != 0)
throw new WeixinMiniProgramExcption(data.ErrMsg);
return data;
}
//校验签名的方法
public static bool ValidateSignature(string sessionKey, string rawData, string signature)
{
var str = rawData + sessionKey;
var utf8Bytes = Encoding.UTF8.GetBytes(str);
var hash = SHA1.Create().ComputeHash(utf8Bytes);
var bit = BitConverter.ToString(hash);
var result = bit.Replace("-", "");
return string.Equals(signature, result, StringComparison.OrdinalIgnoreCase);
}
//解密前端数据的方法
public static JObject DecryptData(string sessionKey, string iv, string encryptedData)
{
var encryptedBytes = Convert.FromBase64String(encryptedData);
using var rij = Rijndael.Create();
rij.KeySize = 128;
rij.Key = Convert.FromBase64String(sessionKey);
rij.IV = Convert.FromBase64String(iv);
rij.Mode = CipherMode.CBC;
rij.Padding = PaddingMode.PKCS7;
using var decryptor = rij.CreateDecryptor();
var json = Encoding.UTF8.GetString(decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length));
return JObject.Parse(json);
}
//解密服务的入口
public async Task<JObject> Decoder(string jsCode,string iv,string encryptedData)
{
var code = await AuthorizationCodeAsync(jsCode);
var info = DecryptData(code.SessionKey, iv, encryptedData);
return info;
}
}
- 用JObject作为返回类型的原因:解密的数据格式是动态的
来个 webapi程序试试
appsettings.json
{
"MiniProgram": {
"AppId": "你的appid",
"AppSecret": "你的secret"
}
}
依赖注入
public void ConfigureServices(IServiceCollection services)
{
services.Configure<WeixinMiniProgramOptions>(Configuration.GetSection("MiniProgram"));
services.AddSingleton<WeixinMiniProgramOAuthService>();
}
搞个控制器试试
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly WeixinMiniProgramOAuthService _service;
public ValuesController(WeixinMiniProgramOAuthService service)
{
_service = service;
}
[HttpPost]
public async Task<ActionResult> WeixinDecoder([FromBody]DecodeVM vm)
{
var data = await _service.Decoder(vm.Iv, vm.JsCode, vm.EncryptedData);
return Ok(data);
}
}
public class DecodeVM
{
public string JsCode { get; set; }
public string Iv { get; set; }
public string EncryptedData { get; set; }
}