今天来说一下微信小程序的授权登录获取用户信息,首先我们看微信提供的小程序开发文档:
https://blog.csdn.net/qq_41971087/article/details/82466647
微信登录的流程和步骤:
步骤:(个人):
第一步:微信小程序调用login和getUserInfo(),拿到code和encryptedData,iv,传入到后台进行业务处理
第二步:拿到code调用登录凭证校验接口去获取用户,openid和session_key
第三步:获取到session_key和encryptedData,iv去进行AES解密,解密成功后就可以拿到用户信息
页面中的代码:
js:
getUserInfo: function (e) {
console.log(5);
console.log(e)
if (e.detail.userInfo) {
app.globalData.userInfo = e.detail.userInfo
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
} else {
this.openSetting();
}
},
login: function () {
console.log(111)
var that = this
var thist = this;
// if (typeof success == "function") {
// console.log(6);
// console.log('success');
// this.data.getUserInfoSuccess = success
// }
wx.login({
success: function (res) {
var code = res.code;
console.log(code);
wx.getUserInfo({
success: function (res) {
console.log(res);
wx.request({
url: app.server.hostUrl + '/api/auth/login_by_weixin.do',//自己的服务接口地址,这里是去拿到code去后台进行业务处理,调用微信接口拿到用户openid和凭证,在解密拿到用户数据
method: 'post',
header: {
'content-type': 'application/x-www-form-urlencoded'
},
data: { encryptedData: res.encryptedData, iv: res.iv, code: code },
success: function (data) {
wx.setStorage({
key: "userif",
data: data.data.userinfo
})
console.info(data);
//4.解密成功后 获取自己服务器返回的结果
if (data.data.code == 1) {
var userInfo_ = data.data.userinfo;
console.log(7);
app.globalData.userInfo = userInfo_
that.setData({
getUserInfoFail: false,
userInf: userInfo_,
hasUserInfo: true
})
thist.setData({
datas: userInfo_,
index: 1
})
console.log(userInfo_)
that.onLoad();
} else {
console.log('解密失败')
}
},
fail: function () {
console.log('系统错误')
}
})
//平台登录
},
fail: function (res) {
console.log(8);
console.log(res);
that.setData({
getUserInfoFail: true
})
}
})
}
})
},
//跳转设置页面授权
openSetting: function () {
var that = this
if (wx.openSetting) {
wx.openSetting({
success: function (res) {
console.log(9);
//尝试再次登录
that.login()
}
})
} else {
console.log(10);
wx.showModal({
title: '授权提示',
content: '小程序需要您的微信授权才能使用哦~ 错过授权页面的处理方法:删除小程序->重新搜索进入->点击授权按钮'
})
}
}
JAVA后台代码Controller层:
/**
*微信登录
* @param code 凭证
* @param encryptedData 用户数据
* @param iv 用户数据
* @param request request作用域:
* @return map
*/
@RequestMapping("/login_by_weixin")
@ResponseBody
public Map loginByWeixin(String code, String encryptedData, String iv, HttpServletRequest request)
{
Map map =new HashMap();
String sendGet=userService.loginByWeixin(code); //根据code去调用接口获取用户openid和session_key
JSONObject json = JSONObject.fromObject(sendGet);
System.out.println("返回过来的json数据:"+json.toString());
String sessionkey=json.get("session_key").toString(); //会话秘钥
String openid=json.get("openid").toString(); //用户唯一标识
try{
//拿到用户session_key和用户敏感数据进行解密,拿到用户信息。
String decrypts=AesCbcUtil.decrypt(encryptedData,sessionkey,iv,"utf-8");//解密
JSONObject jsons = JSONObject.fromObject(decrypts);
String nickName=jsons.get("nickName").toString(); //用户昵称
String jsonsds=jsonsd.get("avatarUrl").toString(); //用户头像
jsons.get("avatarUrl").toString(); //头像
jsons.get("gender").toString();//性别
jsons.get("unionid").toString(); //unionid
jsons.get("city").toString(); //城市
jsons.get("province").toString();//省份
jsons.get("country").toString(); //国家
}catch (Exception e) {
e.printStackTrace();
}
}
这里拿到用户信息自己去做处理,保存到数据库中,这里我就不编写了
userServiceImpl.java:
/**
*微信登录业务实现类:
* @param openid 用户id
* @return User
*/
@Override
public String loginByWeixin(String code, String encryptedData, String iv) {
Map map = new HashMap();
//发送 https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code 获取用户的openid和session_key
//注意这个是 WeChatTool.wxspAppid 是微信小程序的appid 从微信小程序后台获取 WeChatTool.wxspSecret 这个也一样,我这里是用了常量来进行保存方便多次使用
String params = "appid=" + WeChatTool.wxspAppid + "&secret=" + WeChatTool.wxspSecret + "&js_code=" + code + "&grant_type=authorization_code";
String sendGet = Httprequests.sendGet(WeChatTool.url, params); //发起请求拿到key和openid
return sendGet;
}
Httprequests.java(发送网络请求的工具类)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
/**
* User: xxx
*
Date: 14-1-28
*
Version: 1.0
* 描述: http发起请求:
*/
public class Httprequests {
//测试,发送请求是否成功:
public static void main(String[] aegs) {
String string = Httprequests.sendGet("http://v.qq.com/x/cover/kvehb7okfxqstmc.html?vid=e01957zem6o","");
System.out.print(string);
}
//发送GET请求:
public static String sendGet (String url,String param) {
String result ="";
BufferedReader in =null;
try {
String urlNameString = url +"?" +param;
System.out.println("发送的链接请求:"+urlNameString);
URL reaurl = new URL(urlNameString);
URLConnection connection = reaurl.openConnection();
//设置通用
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
//建立实际的连接
connection.connect();
Map> map = connection.getHeaderFields();
//定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
* @param url 发送请求的 URL
* @param param 参数
* @return String 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
}
AesCbcUtil.java(拿用户的session_key和微信小程序传过来的iv和encryptedData进行解密的工具类)
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.management.openmbean.InvalidKeyException;
import org.apache.commons.codec.binary.Base64;
/**
* User: qrn
*
Date: 14-1-28
*
Version: 1.0
* 描述: 解密
*/
public class AesCbcUtil {
/**
* AES解密
*
* @param encryptedData 包括敏感数据在内的完整用户信息的加密数据,
* @param key 秘钥
* @param iv 加密算法的初始向量,
* @param encodingFormat 解密后的结果需要进行的编码
* @return String
* @see Exception
*/
public static String decrypt(String encryptedData,String key, String iv, String encodingFormat) throws Exception {
// initialize();
//被加密的数据
byte[] dataByte = Base64.decodeBase64(data);
//加密秘钥
byte[] keyByte = Base64.decodeBase64(key);
//偏移量
byte[] ivByte = Base64.decodeBase64(iv);
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
parameters.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, encodingFormat);
return result;
}
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidParameterSpecException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
如果上面的执行没有错误的话,就可以拿到用户的信息,这个代码应该是不会出问题,如果有问题请下发评论我会及时的回答,其实微信的开发文档中这些东西以经写的很清楚,希望微信开发的朋友可以认真仔细的观看微信文档,希望这篇文字对大家有用,谢谢
加入群聊: