微信网页授权开发文档
准备工作
微信公众号appid和appSecret及配置相关的ip白名单
配置网页授权域名,具体操作看里面的提示
一. 前端发送请求微信接口获取code
<template>
<view class="main">
<view class="title-bg">
<view class="containers" v-if="isLogin">
<button>
<image :src="headimgurl" mode="aspectFill">image>
<view>{{nickname}}view>
button>
view>
<view class="containers" v-else>
<button @click="login()">
<image src="/static/images/login.png" mode="aspectFill">image>
<view>点击授权登录view>
button>
view>
view>
<view class="menu-bottom">
<view class="menu menu-border-bottom" @click="exitLogin()" v-if="isLogin">
<view class="menul">
<image src="/static/images/exit.png" mode="aspectFill">image>
view>
<view class="menur">
<view class="menur-text">退出登录view>
<view class="menur-img"><image src="/static/images/right.png" mode="aspectFill">image>view>
view>
view>
view>
view>
template>
<script>
export default {
data() {
return {
isLogin: false,
nickname: "", //用户名
headimgurl: "", //头像
openid: "", //openid
}
},
onLoad() {
//强制刷新页面,当从pageB返回到pageA时,刷新页面
window.onpageshow = function (evt) {
setTimeout(function(){
if(evt.persisted){
location.reload(true);
}
});
}
var res_openid = uni.getStorageSync("openid")
if (res_openid != "") {
this.nickname = uni.getStorageSync("nickname");
this.headimgurl = uni.getStorageSync("headimgurl");
this.openid = uni.getStorageSync("openid");
this.isLogin = true
}
},
onShow() {
this.checkWeChatCode()
},
methods: {
//方法:用来提取code
getUrlCode(name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) || [, ''])[1]
.replace(/\+/g, '%20')) || null
},
//检查浏览器地址栏中微信接口返回的code
checkWeChatCode() {
var that = this
let code = that.getUrlCode('code')
let res_code = uni.getStorageSync("hccode")
if(that.openid == "" || that.openid == undefined || that.openid == null){//未登陆
if(code != "" && code != undefined && code != null){
if(res_code != code){
let res = that.$myRequest({
url: 'wechat/apiBaseController/getOpenId',
method:'get',
data: {
code:code
}
})
.then(res =>{
if(res.data.errcode == 0){
//.then是接收正确返回的信息
that.openid = res.data.data.openid
uni.setStorageSync("code",code)
uni.setStorageSync("nickname",res.data.data.nickname)//用户名
uni.setStorageSync("headimgurl",res.data.data.headimgurl)//头像
uni.setStorageSync("openid",res.data.data.openid)//openid
window.history.back()
uni.switchTab({
url:'./my'
})
}else{
window.history.back()
uni.showToast({
title: '登录失败'+err.data.data,
icon:'none',
duration: 1000
})
}
})
.catch(err =>{
window.history.back()
// .catch 返回报错信息
uni.showToast({
title: '请求异常' + err.errMsg,
icon: 'none',
duration: 1500
})
})
}else{
uni.showToast({
title: '已处于登录状态',
icon: 'none',
duration: 1500
})
}
}
}
},
login() {
//请求微信接口,用来获取code
let local = encodeURIComponent(window.location.href); //获取当前页面地址作为回调地址
//通过微信官方接口获取code之后,会重新刷新设置的回调地址【redirect_uri】,之后会继续进入到onload()方法
var appid = "";//你的appid
location.href =
"https://open.weixin.qq.com/connect/oauth2/authorize?appid="+
appid +
"&redirect_uri="+local+"&response_type=code&scope=snsapi_userinfo&state=STATE&connect_redirect=1#wechat_redirect"
},
exitLogin() {
var that = this
uni.showModal({
title: "温馨提示",
content: "你确定退出登录吗?",
cancelColor:'#999494',
confirmColor: '#203c42',//确定文字的颜色
success(res) {
if (res.confirm) {
that.isLogin = false
uni.removeStorageSync("nickname");
uni.removeStorageSync("headimgurl");
uni.removeStorageSync("openid");
uni.removeStorageSync("code");
// uni.removeStorageSync("qzstaffLogin");//职工登录
uni.showToast({
title: '退出成功',
icon: 'none',
duration: 1000
})
setTimeout(()=>{
uni.switchTab({
url:'../index/anotherIndex'
})
},1000)
}
}
})
},
}
}
script>
<style>
page{
background: #f7f7f7;
}
.title-bg{
height: 380rpx;
background-image: url(../../static/images/my_bg.png);
background-size: 100% 100%;
}
.title-bg .containers {
margin: auto;
text-align: center;
padding-top: 80rpx;
height: 300rpx;
backdrop-filter: blur(4rpx);
}
.title-bg .containers button{
display: block;
background: none;
padding: 0;
border: 0;
line-height: 0;
width: 300rpx;
}
.title-bg .containers button::after {
border: none
}
.title-bg .containers button image{
width: 170rpx;
height: 170rpx;
border-radius: 50%;
}
.title-bg .containers button view{
margin-top: 10rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 38rpx;
color: #222222;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-break: break-all;
}
.menu-border-bottom{
border-bottom: 1px solid #f2f2f2;
}
.main .menu-bottom{
margin-top: 20rpx;
}
.main .menu-bottom:last-child{
padding-bottom: 150rpx;
}
.main .quit {
text-align: center;
padding: 40rpx 0px;
color: #90948d;
margin-top: 20px;
}
style>
创建request.js写入如下代码
// 定一个常量 存储请求地址
export const BASE_URL = 'hhttp://localhost:8901/'//springboot接口路径,上线这里配置成域名就好
export const myRequest = (options)=>{
return new Promise((resolve, reject)=>{
// 封装主体:网络请求
uni.request({
url: BASE_URL + options.url,
header: {},
data: options.data || {},
method: options.method || 'GET',// 默认值GET,如果有需要改动,在options中设定其他的method值
success: (res) => {
// console.log(res.data); // 控制台显示数据信息
resolve(res)
},
fail: (err) =>{
// 页面中弹框显示失败
uni.showToast({
title: '请求接口失败',
icon:'none',
duration: 2000
})
// 返回错误消息
reject(err)
}
})
}
)
}
3.全局挂载requests.js中的myRequest方法
main.js中写入如下代码
import App from './App'
import Vue from 'vue'
import store from './store/index.js'
import uView from 'uview-ui'
import { myRequest } from './utils/request.js';//自己创建的request.js路径
Vue.config.productionTip = false
// vuex
Vue.prototype.$store = store
// 引用uView
Vue.use(uView)
// 挂载到全局,让所有的页面都能调用myRequest方法
Vue.prototype.$myRequest = myRequest
App.mpType = 'app'
const app = new Vue({
...App,
store
})
app.$mount()
二. 通过code获取相关的微信用户头像等数据
import cc.jinjun.febs.common.controller.BaseController;
import cc.jinjun.febs.common.utils.HttpUtil;
import cc.jinjun.febs.pay.wechat.WechatEnum;
import cc.jinjun.febs.wechat.entity.ResultData;
import cc.jinjun.febs.wechat.entity.WxUserInfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
//获取微信用户openid唯一标识
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/wechat/apiLoginController")
@CrossOrigin
public class ApiLoginController extends BaseController {
@ResponseBody
@GetMapping("/getOpenId")
public ResultData getOpenId(String code) throws IOException {
try {
// String result = new GetOpenid().getResult(code);
// JSONObject jsonObject = JSON.parseObject(result);
// System.out.println(jsonObject);
// System.out.println("---------------------"+jsonObject.getString("openid"));
String url = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=" + WechatEnum.appId +//WechatEnum.appId更换成自己的appid
"&secret=" + WechatEnum.appSecret +//WechatEnum.appSecret 更换成自己的appSecret
"&code=" + code +
"&grant_type=authorization_code";
String result_url = HttpUtil.doPost(url);
log.info("请求获取access_token:" + result_url);
//返回结果的json对象
JSONObject resultObject = JSON.parseObject(result_url);
//请求获取userInfo
String infoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=" + resultObject.getString("access_token") +
"&openid=" + resultObject.getString("openid") +
"&lang=zh_CN";
String infoUrl_url = HttpUtil.doPost(infoUrl);
log.info("请求获取access_token:" + infoUrl_url);
JSONObject userJsonObject = JSON.parseObject(infoUrl_url);
WxUserInfo wxUserInfo = new WxUserInfo(userJsonObject.getString("nickname"), userJsonObject.getString("headimgurl"), userJsonObject.getString("openid"));
if (wxUserInfo.getOpenid() == null) {
return new ResultData(201, "授权登录失败", wxUserInfo);
}
return new ResultData(0, "登录成功", wxUserInfo);
} catch (Exception e) {
return new ResultData(501, "登录失败", e.getMessage());
}
}
}
WxUserInfo 类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxUserInfo {
private String nickname;//用户名
private String headimgurl;//头像
private String openid;//openid
}
ResultData 类
public class ResultData<T> {
//返回状态码,为0表示结果正确,不为0表示结果异常
private Integer errcode;
//结果描述
private String errmsg;
//返回数据
private T data;
public ResultData() {
}
public ResultData(Integer errcode, String errmsg, T data) {
this.errcode = errcode;
this.errmsg = errmsg;
this.data = data;
}
public Integer getErrcode() {
return errcode;
}
public void setErrcode(Integer errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
return "ResultData{" +
"errcode=" + errcode +
", errmsg='" + errmsg + '\'' +
", data=" + data +
'}';
}
}
HttpUtil 类
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpStatus;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @ClassName: HttpUtil
* @USER: Administrator
* @DATE: 2020/4/21
* @TODO:
**/
public class HttpUtil {
public static String doGet(String urlPath, HashMap<String, Object> params)
throws Exception {
StringBuilder sb = new StringBuilder(urlPath);
if (params != null && !params.isEmpty()) { // 说明有参数
sb.append("?");
Set<Map.Entry<String, Object>> set = params.entrySet();
for (Map.Entry<String, Object> entry : set) { // 遍历map里面的参数
String key = entry.getKey();
String value = "";
if (null != entry.getValue()) {
value = entry.getValue().toString();
// 转码
value = URLEncoder.encode(value, "UTF-8");
}
sb.append(key).append("=").append(value).append("&");
}
sb.deleteCharAt(sb.length() - 1); // 删除最后一个&
}
URL url = new URL(sb.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000); // 5s超时
conn.setRequestMethod("GET");
if (conn.getResponseCode() == HttpStatus.OK.value()) {// HttpStatus.SC_OK ==
// 200
BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
StringBuilder sbs = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sbs.append(line);
}
return sbs.toString();
}
return null;
}
public static String doPost(String url, Map<String, Object> 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).toString());
}
}
URI uri = builder.build();
// 创建http Post请求
HttpPost httpPost = new HttpPost(uri);
// 执行请求
response = httpclient.execute(httpPost);
// 判断返回状态是否为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) throws Exception {
return doGet(url, null);
}
public static String doPost(String url) {
return doPost(url, null);
}
}
maven
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.3version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.83version>
<scope>compilescope>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.8.0version>
dependency>
注意
完成代码后将后端项目部署到微信公众号IP白名单对应的服务器运行,不然获取不到access_token
前端部署后要分配域名,域名跟网页授权域名对应,后端项目也可以分配域名
多多指教,共同进步丫