1、微信小程序获取用户手机号,每次都会弹窗询问
2、获取用户信息(包括昵称、性别、城市、openid等),只弹窗一次 (根据手机号做授权验证用不到这里)
3、微信小程序可以利用缓存,但是有时间限制
4、获取手机号和openid—>是需要到自己服务器后台解密—>解密需要用到session_key—>session_key需要微信login接口(从前端)获取code然后传到后台服务器调用微信接口获取
5、通过自己服务器后台使用code获取数据之后,code则会失效
官方文档
uni-app
如何查看小程序的AppID和AppSecret?
ASP.NET WEBAPI作服务端开发小程序实现微信授权用户登录实例
using AIOWeb.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
namespace AIOWeb
{
///
/// wxapi 的摘要说明
///
public class wxapi : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string code = "";
string iv = "";
string encryptedData = "";
try
{
code = HttpContext.Current.Request.QueryString["code"].ToString();
iv = HttpContext.Current.Request.QueryString["iv"].ToString();
encryptedData = HttpContext.Current.Request.QueryString["encryptedData"].ToString();
}
catch (Exception ex)
{
context.Response.Write(ex.ToString());
}
string Appid = "wxdb2641f85b04f1b3";
string Secret = "8591d8cd7197b9197e17b3275329a1e7";
string grant_type = "authorization_code";
//向微信服务端 使用登录凭证 code 获取 session_key 和 openid
string url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + Appid + "&secret=" + Secret + "&js_code=" + code + "&grant_type=" + grant_type;
string type = "utf-8";
AIOWeb.Models.GetUsersHelper GetUsersHelper = new AIOWeb.Models.GetUsersHelper();
string j = GetUsersHelper.GetUrltoHtml(url, type);//获取微信服务器返回字符串
//将字符串转换为json格式
JObject jo = (JObject)JsonConvert.DeserializeObject(j);
result res = new result();
try
{
//微信服务器验证成功
res.openid = jo["openid"].ToString();
res.session_key = jo["session_key"].ToString();
}
catch (Exception)
{
//微信服务器验证失败
res.errcode = jo["errcode"].ToString();
res.errmsg = jo["errmsg"].ToString();
}
if (!string.IsNullOrEmpty(res.openid))
{
//用户数据解密
GetUsersHelper.AesIV = iv;
GetUsersHelper.AesKey = res.session_key;
string result = GetUsersHelper.AESDecrypt(encryptedData);
//存储用户数据
JObject _usrInfo = (JObject)JsonConvert.DeserializeObject(result);
userInfo userInfo = new userInfo();
userInfo.openId = _usrInfo["openId"].ToString();
try //部分验证返回值中没有unionId
{
userInfo.unionId = _usrInfo["unionId"].ToString();
}
catch (Exception)
{
userInfo.unionId = "unionId";
}
userInfo.nickName = _usrInfo["nickName"].ToString();
userInfo.gender = _usrInfo["gender"].ToString();
userInfo.city = _usrInfo["city"].ToString();
userInfo.province = _usrInfo["province"].ToString();
userInfo.country = _usrInfo["country"].ToString();
userInfo.avatarUrl = _usrInfo["avatarUrl"].ToString();
object watermark = _usrInfo["watermark"].ToString();
object appid = _usrInfo["watermark"]["appid"].ToString();
object timestamp = _usrInfo["watermark"]["timestamp"].ToString();
#region
//创建连接池对象(与数据库服务器进行连接)
SqlConnection conn = new SqlConnection("server=127.0.0.1;database=Test;uid=sa;pwd=1");
//打开连接池
conn.Open();
//创建命令对象
string Qrystr = "SELECT * FROM WeChatUsers WHERE openId='" + userInfo.openId + "'";
SqlCommand cmdQry = new SqlCommand(Qrystr, conn);
object obj = cmdQry.ExecuteScalar();
if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))
{
string str = "INSERT INTO WeChatUsers ([UnionId] ,[OpenId],[NickName],[Gender],[City],[Province],[Country],[AvatarUrl],[Appid],[Timestamp],[Memo],[counts])VALUES('" + userInfo.unionId + "','" + userInfo.openId + "','" + userInfo.nickName + "','" + userInfo.gender + "','" + userInfo.city + "','" + userInfo.province + "','" + userInfo.country + "','" + userInfo.avatarUrl + "','" + appid.ToString() + "','" + timestamp.ToString() + "','来自微信小程序','1')";
SqlCommand cmdUp = new SqlCommand(str, conn);
// 执行操作
try
{
int row = cmdUp.ExecuteNonQuery();
}
catch (Exception ex)
{
context.Response.Write(ex.ToString());
}
}
else
{
//多次访问,记录访问次数counts 更新unionId是预防最初没有,后期关联后却仍未记录
string str = "UPDATE dbo.WeChatUsers SET counts = counts+1,UnionId = '" + userInfo.unionId + "' WHERE OpenId='" + userInfo.openId + "'";
SqlCommand cmdUp = new SqlCommand(str, conn);
int row = cmdUp.ExecuteNonQuery();
}
//关闭连接池
conn.Close();
#endregion
//返回解密后的用户数据
context.Response.Write(result);
}
else
{
context.Response.Write(j);
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
GetUsersHelper 帮助类
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace AIOWeb.Models
{
public class GetUsersHelper
{
///
/// 获取链接返回数据
///
/// 链接
/// 请求类型
///
public string GetUrltoHtml(string Url, string type)
{
try
{
System.Net.WebRequest wReq = System.Net.WebRequest.Create(Url);
// Get the response instance.
System.Net.WebResponse wResp = wReq.GetResponse();
System.IO.Stream respStream = wResp.GetResponseStream();
// Dim reader As StreamReader = New StreamReader(respStream)
using (System.IO.StreamReader reader = new System.IO.StreamReader(respStream, Encoding.GetEncoding(type)))
{
return reader.ReadToEnd();
}
}
catch (System.Exception ex)
{
return ex.Message;
}
}
#region 微信小程序用户数据解密
public static string AesKey;
public static string AesIV;
///
/// AES解密
///
/// 输入的数据encryptedData
/// key
/// 向量128
/// 解密后的字符串
public string AESDecrypt(string inputdata)
{
try
{
AesIV = AesIV.Replace(" ", "+");
AesKey = AesKey.Replace(" ", "+");
inputdata = inputdata.Replace(" ", "+");
byte[] encryptedData = Convert.FromBase64String(inputdata);
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Key = Convert.FromBase64String(AesKey); // Encoding.UTF8.GetBytes(AesKey);
rijndaelCipher.IV = Convert.FromBase64String(AesIV);// Encoding.UTF8.GetBytes(AesIV);
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
string result = Encoding.UTF8.GetString(plainText);
return result;
}
catch (Exception)
{
return null;
}
}
#endregion
}
}
===============================================后补:实体类========================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace AIOWeb.Models
{
public class wechat
{
}
#region 实体类
///
/// 微信用户类
///
public class userInfo
{
public string openId { get; set; }
public string nickName { get; set; }
public string gender { get; set; }
public string city { get; set; }
public string province { get; set; }
public string country { get; set; }
public string avatarUrl { get; set; }
public string unionId { get; set; }
public data watermark { get; set; }
}
///
/// 微信用户数据水印
///
public class data
{
public string appid { get; set; }
public string timestamp { get; set; }
}
///
/// 微信小程序验证返回结果
///
public class result
{
public string openid { get; set; }
public string session_key { get; set; }
public string errcode { get; set; }
public string errmsg { get; set; }
}
#endregion
}
微信小程序获取手机号需要完成认证,才能获取得到
一、搭建后台服务器(WebApI)
新建webapi2空控制器 OnLoginController
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Web.Http;
using WebApplication1.Models;//引入实体类命名空间
using System.Web.Http.Cors;//跨域请求命名空间
namespace WebApplication1.Controllers
{
//跨域请求
[EnableCors(origins:"*",headers:"*",methods:"*")]
[RoutePrefix("api/OnLogin")]
public class OnLoginController : ApiController
{
[Route("Get")]
[HttpGet]
public object Get(string code)
{
string cod = code;
string html = string.Empty;
string url = "https://api.weixin.qq.com/sns/jscode2session?appid=wxb2f63b12a7371f2a&secret=110dc84617c235b5809a7f5d8d43af3a&js_code="+cod+"&grant_type=authorization_code";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Method = "GET";
request.ContentType = "text/html;charset=UTF-8";
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
Stream ioStream = response.GetResponseStream();
StreamReader sr = new StreamReader(ioStream, Encoding.UTF8);
html = sr.ReadToEnd();
sr.Close();
ioStream.Close();
response.Close();
RepParamrep rep = JsonConvert.DeserializeObject(html);
return rep;
}
}
}
新建实体类RepParamrep ,保存session_key和open_id
namespace WebApplication1.Models
{
public class RepParamrep
{
public string session_key { get; set; }
public string openid { get; set; }
}
}
解析手机号码
[Route(“Get”)]
[HttpGet]
public string Get(string encryptedData, string iv, string session_key)
{
string _telPhone = getPhoneNumber(encryptedData, iv, session_key);
return _telPhone;
}
private string getPhoneNumber(string encryptedData, string IV, string Session_key)
{
try
{
byte[] encryData = Convert.FromBase64String(encryptedData);
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Key = Convert.FromBase64String(Session_key);
rijndaelCipher.IV = Convert.FromBase64String(IV);
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
byte[] plainText = transform.TransformFinalBlock(encryData, 0, encryData.Length);
string result = Encoding.Default.GetString(plainText);
dynamic model = Newtonsoft.Json.Linq.JToken.Parse(result) as dynamic;
return model.phoneNumber;
}
catch (Exception ex)
{
return "";
}
}
二、设计前端界面及逻辑
//index.wxss
//index.js
const app = getApp();
Page({
data: {
userPhone: '',
userNicheng: '',
hid1: false,
hid2: true
},
bindGetUserInfo: function(e) {
this.setData({
userNicheng: e.detail.userInfo.nickName,
hid1: true,
hid2: false
})
},
getPhoneNumber: function(e) {
var that = this;
console.log("getPhoneNumberok" + e.detail.errMsg);
if (e.detail.errMsg == "getPhoneNumber:ok") {
//端口号是由后端服务器生成
wx.request({
url: 'https://localhost:44358/api/OnLogin/Get',
data: {
encryptedData: e.detail.encryptedData,
iv: e.detail.iv,
session_key: app.globalData.session_key
},
method: "get",
success: function(res) {
console.log(res)
that.setData({
userPhone: res.data
})
},
fail:function(res){
console.log(res.errMsg)
}
})
}
}
})
//app.js
App({
globalData:{
session_key:'',
openid:''
},
onLaunch: function() {
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
console.log(res)
if (res.code) {
console.log("code========" + JSON.stringify(res));
//发起网络请求
wx.request({
url: 'https://localhost:44358/api/OnLogin/Get',
data: {
code: res.code
},
success: data => {
console.log("data" + JSON.stringify(data.data));
this.globalData.session_key = data.data.session_key;
this.globalData.openid = data.data.openid;
console.log("openid" + this.globalData.openid);
},
fail:data=>{
console.log(data)
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
}
})
<% @ webhandler language="C#" class="AverageHandler" %>
using System;
using System.Net;
using System.Web;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using LitJson;
public class AverageHandler : IHttpHandler
{
public bool IsReusable
{ get { return true; } }
public void ProcessRequest(HttpContext ctx)
{
ctx.Response.ContentType = "application/json";
HttpRequest Request = ctx.Request;
string text = Request["encryptedData"];
string IV = Request["iv"];
//小程序appid和appsecret配置
string appid = "小小星星亮晶晶";
string secret = "小小星星亮晶晶";
string code = Request["code"];//微信获取登录的口令
Stream s_re = WebRequest.Create("https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code").GetResponse().GetResponseStream();
StreamReader sr = new StreamReader(s_re, Encoding.UTF8);
string strLine = sr.ReadToEnd();
sr.Close();
try
{
JsonData jo = JsonMapper.ToObject(strLine);
string Key = jo["session_key"].ToString();
//string weixinID = jo["openid"].ToString();
string str= AES_decrypt(text,Key,IV);
ctx.Response.Write(str);
}
catch (Exception ex)
{
//return "";
}
}
public string AES_decrypt(string encryptedDataStr, string key, string iv)
{
RijndaelManaged rijalg = new RijndaelManaged();
//-----------------
//设置 cipher 格式 AES-128-CBC
rijalg.KeySize = 128;
rijalg.Padding = PaddingMode.PKCS7;
rijalg.Mode = CipherMode.CBC;
rijalg.Key = Convert.FromBase64String(key);
rijalg.IV = Convert.FromBase64String(iv);
byte[] encryptedData= Convert.FromBase64String(encryptedDataStr);
//解密
ICryptoTransform decryptor = rijalg.CreateDecryptor(rijalg.Key, rijalg.IV);
string result;
using (MemoryStream msDecrypt = new MemoryStream(encryptedData))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
result = srDecrypt.ReadToEnd();
}
}
}
return result;
}
}