对接后台登录流程
微信官方早都已经禁止开发者直接通过 api 获取用户信息数据了,大家拿个用户的 openid 注册好,剩下的让用户填写就行了。
先上官方的经典登录流程图:
步骤拆分解析:
- 前端通过 调用官方 API
wx.login
,将回调中的code
临时登陆凭证传递给(请求)后台 - 后台去请求微信的接口
https://api.weixin.qq.com/sns/jscode2session
。具体用法参考 官方文档 - 后台请求该接口的响应成功的数据中可以拿到两个值
openid
和session_key
。其中openid
是唯一值,可以当作用户标识,比如判断该用户是否存在,是否注册该用户等。session_key
自行处理。
如果需要获取用户信息(现在用户信息毛都没有,获取也没用,别获取了),需要在 wx.login
之前调用 wx.getUserProfile
将 rawData
和 signature
联合 code 一并传递给后台,后台通过 session_key
和 rawData
来反解析 signature
的正确性。
根据现在微信官方的说法,注册时添加微信用户真实信息(头像昵称)是不可能的,前后端交互时,通过
wx.login
传递一个 code 仅注册就可以,其它参数目前完全没用
前端代码
不是我不用 wx.getUserProfile
,而是这个 api 真没啥信息可获取了,老老实实拿个 openid 注册就行了。
wx.login({
success(res) {
wx.request({
url: 'http://localhost:8888/testApi/wx/login',
data: {
// encryptedData 和 iv 是用来解析私密用户信息的,但是现在啥也获取不到了,所以没用
code: res.code,
// encryptedData: InfoRes.encryptedData,
// iv: InfoRes.iv,
// rawData: InfoRes.rawData,
// signature: InfoRes.signature,
},
}).then((res) => {
// 登录认证成功,后台一般会返回登陆凭证(token),存储使用即可
});
},
fail(err) {
console.log(err.errMsg);
},
});
后端代码
请求第三方(微信)示例
请求第三方接口,这里给出两种获取第三方接口的代码方式,任选其中一种即可。
- pom 中集成 httpclient 包。
HttpClientUtils.java
public class HttpClientUtil {
public static String doGet(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http GET请求
HttpGet httpGet = new HttpGet(uri);
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doGet(String url) {
return doGet(url, null);
}
public static String doPost(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, param.get(key)));
}
// 模拟表单
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);
}
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static String doPost(String url) {
return doPost(url, null);
}
public static String doPostJson(String url, String json) {
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
}
使用
Map<String, String> params = new HashMap<>();
// .... 参数添加 params.put("...","...")
String s = HttpClientUtil.doPost(url, params);
SONObject object = JSON.parseObject(s);
- 使用 Springboot 自带的 RestTemplate
RestTemplateUtil
public class RestTemplateUtil {
public static JSONObject doPost(String url, MultiValueMap<String, Object> param){
RestTemplate restTemplate=new RestTemplate();
String s = restTemplate.postForObject(url, param, String.class);
return JSONObject.parseObject(s);
}
}
使用
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
// .... 参数添加 params.add("...","...")
JSONObject object = RestTemplateUtil.doPost(url, params);
登录流程对接
// 现在 rawData 和 signature 已经没什么用了,所以这两个参数相关的逻辑可以删除,此处保留仅做记录
public R wxLogin(String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session";
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("appid",appid);
params.add("secret",secret);
params.add("js_code",code);
params.add("grant_type",grantType);
JSONObject object = RestTemplateUtil.doPost(url, params);
System.out.println(object);
//接收微信接口服务 获取返回的参数,这里拿到 openid 就足够了,后边的签名校验没啥必要
String openid = object.getString("openid");
String sessionKey = object.getString("session_key");
//校验签名 小程序发送的签名signature与服务器端生成的签名signature2 = sha1(rawData + sessionKey)
// String signature2 = DigestUtils.sha1Hex(rawData + sessionKey);
// System.out.println(signature2);
// System.out.println(openid);
// if(!signature.equals(signature2)){
// return R.fail("签名校验失败");
// }
// SONObject rawDataJson = JSONObject.parseObject(rawData);
// return R.ok(rawDataJson);
// --------这里可以使用 openid 判断用户是否注册,将用户信息插入数据库
}
获取用户信息
通过 API 调用方式直接获取用户信息的方式已经完全没有了,只能让用户自己手动完善个人信息,类似于表单填写,但在此基础上,微信官方提供了相应的开放能力。
此处使用原生的小程序做示例,Taro 和 uniapp 的使用逻辑相同。
获取用户昵称
小程序的 input 组件配置 type="nickname"
<input type="nickname" model:value="{{ nameValue }}" placeholder="请输入昵称" />
Page({
data: {
nameValue: '',
},
onl oad(options) {
const { name } = options;
this.setData({
nameValue: name,
});
},
onSubmit() {
// 此处可将填充的用户昵称提交给后端做更新
console.log(this.data.nameValue);
},
});
获取用户头像
小程序的 button 组件需设置 open-type="chooseAvatar"
,并绑定对应的事件,获取用户的(上传)头像临时地址,将其传给后端进行信息保存。
<button open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image src="{{ avatarUrl }}" />
</button>
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0';
Page({
data: {
avatarUrl: defaultAvatarUrl,
},
async onChooseAvatar(e) {
const { avatarUrl = '' } = e.detail;
const { data, code } = await uploadImg(avatarUrl); // 此处将头像上传到后端,并返回图片 url 地址
code === 200 &&
this.setData({
avatarUrl: data,
});
},
});
标签:String,登录,url,对接,用户,params,new,授权,response
From: https://www.cnblogs.com/jsonq/p/18402233