按照惯例,先上官网链接 传送门
很多入门小伙伴可能看不懂官网给的图解,这里简单解释下
1. 从小程序端,用户授权wx.login(),得到 code
2. 在小程序端,拿着 code,给到自己的后台服务器
3. 在自己后台, 拿着前台传来的code,和自己的AppId,Secret,去请求微信服务接口
4. 微信服务接口,把用户的openId 和 session_key返回给你的后台服务器
5. 拿着返回的 openId 去开发后续的用户登录程序.
6. 如何获取 appId和Secret,请看文末
获取流程如下:
- 前端(小程序端)
- - user.wxml
- - user.js
- - app.js
- 后端(开发者服务器端)
- - 在pom.xml中导入jar包
- - 准备参数(AppId & secret)
- - Ctrl+C+V 工具包
- - 执行主要功能-获取openId
- - 将获取到的openId做登录业务处理
查看自己的 AppId和Secret 传送门
在app.js页面中,增加自己的后台地址
globalData: {
userInfo: null,
base_url: "http://localhost:8080"
}
在user.wxml中,写上简陋的用户信息
<!--pages/user/user.wxml-->
<view class="container">
<view class="userinfo">
<!-- 如果可以使用用户信息,则显示用户信息 -->
<block wx:if="{{canIUseOpenData}}">
<view class="userinfo-avatar" bindtap="bindViewTap">
<open-data type="userAvatarUrl" ></open-data>
</view>
<view class="userinfo-nickname">
<open-data type="userNickName"></open-data>
</view>
</block>
<!-- 反之, 显示按钮, 按钮用于授权登录用户信息 -->
<block wx:else="{{!hasUserInfo}}">
<button bindtap="login" >授权登录</button>
</block>
</view>
</view>
user.js
// pages/user/user.js
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
motto: 'Hello World',
userInfo: {},
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo'),
canIUseGetUserProfile: false,
canIUseOpenData: false// wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName') // 如需尝试获取用户信息可改为false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
login(){
console.log("进入login方法");
if(false){
// 如果缓存中存在用户信息, 将缓存的数据赋值到userinfo中
}
wx.login({
success(e){
console.log(e.code);
console.log(app.globalData);
wx.request({
url: app.globalData.base_url + '/wechat/getUserInfo',
method: 'POST',
header: {
'content-type': 'application/x-www-form-urlencoded'
},
data: {
code: e.code
},
success: (r) => {
console.log("login() => wx.login => 用code换取登录信息请求成功!");
console.log(r.data);
const userInfo = r.data.object
// 将返回的数据保存到全局的缓冲中,方便其他页面使用
// wx.setStorage({ key: 'userInfo', data: userInfo })
},
fail: (res) => {
console.warn("login() => wx.login => 用code换取登录信息请求失败");
},
complete: (res) => {
},
})
}
})
// wx.openSetting({
// withSubscriptions: true,
// })
}
开发者服务器(后端)
在pom.xml中导入jar包
<dependencies>
<!-- ... 省略掉的其他jar包 ... -->
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.5</version>
</dependency>
<!-- json -->
<!--https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>
</dependencies>
在controller包的同级目录中新建util包(若已存在util就跳过)
在 util 包下,新建 wechat包和http包
wechat包下创建类,命名为: WeChatConfig
更改appid和secret为自己的
package com.leo.自己的项目域名.util.wechat;
public class WeChatConfig {
// 请求网址
public static final String WX_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
// 你的微信AppId
public static final String WX_LOGIN_APPID = "自己的appidwxxxxxxb13";
// 你的微信SECRET
public static final String WX_LOGIN_SECRET = "自己的SECRET-33b1720a396a090";
// 固定参数
public static final String WX_LOGIN_GRANT_TYPE = "authorization_code";
}
在http包下创建工具类,命名为 HttpClientUtil
注意引入的包
package com.leo.自己的项目名.util.http;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
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;
}
}
在controller包下创建类,命名为: WeChatController
类中方法的返回类型是自己定义的返回值类型,替换为自己的返回值即可
package com.leo.自己项目名.controller;
import com.alibaba.fastjson.JSONObject;
import com.leo.自己项目名.pojo.Result;
import com.leo.自己项目名.util.http.HttpClientUtil;
import com.leo.自己项目名.util.wechat.WeChatConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController // 控制器类的注解
@Slf4j // lombok的日志类的注解
@RequestMapping("/wechat") // 请求映射的注解
public class WeChatController {
@PostMapping("/getUserInfo") // post请求的注解
public Result user_login(@RequestParam("code") String code){
// 配置请求参数
Map<String, String> param = new HashMap<>();
param.put("appid", WeChatConfig.WX_LOGIN_APPID);
param.put("secret", WeChatConfig.WX_LOGIN_SECRET);
param.put("js_code", code);
param.put("grant_type", WeChatConfig.WX_LOGIN_GRANT_TYPE);
// 发送请求
String wxResult = HttpClientUtil.doGet(WeChatConfig.WX_LOGIN_URL, param);
log.info(wxResult);
JSONObject json = JSONObject.parseObject(wxResult);
String open_id = json.get("openid").toString();
String session_key = json.get("session_key").toString();
// 根据返回的user实体类,判断用户是否是新用户,不是的话,更新最新登录时间,是的话,将用户信息存到数据库
// 封装返回小程序
Map<String, String> result = new HashMap<>();
result.put("session_key", session_key);
result.put("open_id", open_id);
return new Result(1,"ok",result); // 自己定义的返回类
}
}
完成! 打开小程序开发端,点击授权登录,即可看见控制台返回的重要信息.
将小程序的 data中的canIUseOpenData:false 注释掉,就可以正常开发后续登录业务了
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html