摘要
通过微信网页授权接口,获取用户信息(头像,昵称等)
前置准备
- 安装nginx,用于后续同一域名的反向代理,代理到页面和后端接口 下载地址
实现逻辑
-
通过nginx,将页面和后端接口,代理到同一域名下
-
前端部分,通过授权,获取通过微信重定向后带过来的用户code
-
通过code,调用后端接口,请求获得用户信息
-
展示用户信息
具体实现
修改web项目的接口
之前我吧web项目的端口设置为了80,好让natapp,通过域名直接访问到web项目,现在将web项目的端口改成8081,然后用nginx反向代理访问到本地web项目
修改web项目的基础路径
基础路径有点类似后端的项目名,原来是http://localhost:8081/就能访问的页面,现在要通过http://localhost:8081/demo/来访问
下载并配置nginx
[下载地址](nginx: download)
我本地是windows环境,就下了windoows版本了
修改conf目录中的配置,添加一个自己的目录conf,里面放我们自己的nginx配置,在conf/nginx.conf中加入我们自己配置的目录地址
意思就是,conf目录下所有后缀名为conf的文件纳入进来
include conf/*.conf;
我们自己的nginx配置
这样,就可以通过域名http://xbjh.natapp1.cc/demo/访问到本地项目了,这个地址后面会用在微信开发者工具中
server{
listen 80;
server_name xbjh.natapp1.cc;
location / {
index index.htm index.html index.php sign_in;
root /home/app/prod/xbjh;
}
# web项目的代理
location /demo/ {
proxy_pass http://localhost:8081; # 设置代理目标
proxy_set_header Host $host; # 设置代理请求头
proxy_set_header X-Real-IP $remote_addr;
}
# 后端接口项目的代理
location ~ /demoapi/(.*) {
rewrite ^/demoapi/(.*) /wxtoken/$1 break; # 重写 URL
proxy_pass http://localhost:10200; # 设置代理目标
proxy_set_header Host $host; # 设置代理请求头
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 如果需要传递查询参数,可以添加以下一行:
# proxy_set $args $args;
}
access_log /home/app/log/nginx/xbjh.log;
}
项目改造
调整首页信息和增加一个授权页面,授权页面就一个按钮,用于调用授权获取code
这块是服务端调用的接口
idnex.vue
<template>
<view class="content">
<template>
<view class="logo-container">
<u-avatar class="avatar" :src="src" mode="square" :size ="100"></u-avatar>
<p>昵称:{{nickname}}</p>
</br>
</view>
</template>
<template>
<view class="form-content">
<u-button type="primary" v-on:click="toauth()">授权页面</u-button>
<template v-if="form.wx_code !== ''">
<u-form :model="form" ref="uForm" label-position="top" label-width="500">
<u-form-item label="微信Code"><u-input v-model="form.wx_code" /></u-form-item>
<u-button type="primary" v-on:click="getUserInfo()">获取用户信息</u-button>
</u-form>
</template>
</view>
</template>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello',
form: {
wx_code: ''
},
src: 'https://gitee.com/flygoa/markdown-img/raw/master/markdown/729abc9a-3844-4498-b041-71e7f3e1a52d.jpeg',
nickname: ''
}
},
onLoad(option) {
//第二种
this.paraString = window.location.href //还可以 window.location.search.substring()
if(this.getQueryVariable('code')){
this.form.wx_code = this.getQueryVariable('code') //code是url后面带的
}
console.log("wx_code",this.form.wx_code)
},
methods: {
toauth:function(){
uni.navigateTo({
url:'/pages/auth/auth'
})
},
// 获取地址栏中的参数
getQueryVariable(variable) {
var query = this.paraString;
var rooms = query.split('?');
for (var i = 0; i < rooms.length; i++) {
var pair = rooms[i].split('=');
if (pair[0] == variable) {
return (pair[1].split('&'))[0]
}
}
//或者拼接&后面的值
var vars = query.split('&')
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=')
if (pair[0] == variable) {
return pair[1]
}
}
},
// 获取用户信息
getUserInfo(){
// 发送 GET 请求
uni.request({
url: 'http://xbjh.natapp1.cc/demoapi/api/weChat/getWxInfoByCode',// 请求的 URL
data: {
code: this.form.wx_code
},
method: 'GET', // 请求方法
success: (res) => {
// 请求成功时的回调函数
if(res.data.code == 10001){
console.log('请求成功', res.data);
if(res.data.data){
this.src = res.data.data.headimgurl
this.nickname = res.data.data.nickname
}
}
},
fail: (err) => {
console.error('请求失败', err);
}
});
}
}
}
</script>
<style>
.content {
margin: 0 50rpx;
}
.logo-container {
text-align: center; /* 居中对齐 */
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.avatar {
margin-top: 20rpx;
margin-bottom: 20rpx;
margin-left: auto;
margin-right: auto;
}
</style>
auth.vue
<template>
<view class="content">
<u-button class="auth" type="primary" v-on:click="auth()">点击授权</u-button>
</view>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
auth:function(){
location.href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=自己的appidd&redirect_uri=http%3A%2F%2Fxbjh.natapp1.cc%2Fdemo%2F%23%2F&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect"
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 0 60rpx;
}
.auth {
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
</style>
在微信公众平台中,配置网页授权域名
如果不配置的话,会提示“redirect uri 参数错误”
启动nginx,在微信开发者工具中访问域名网址
这样就能拿到重定向回来的code
后端代码
获取用户信息,这步需要调用服务端接口
因为appid和secret比较敏感,微信建议在服务端进行请求
服务端是springboot实现,就加了一个controller
有可能会提示IP未加入白名单,在微信公众平台将本地IP加入即可
核心处理类:WeChatController.java
package com.lc.wxtoken.business.controller;
import com.alibaba.fastjson.JSONObject;
import com.lc.wxtoken.business.entity.R;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Collections;
/**
* 微信access token 控制类
*/
@Controller
@RequestMapping("/api/weChat")
public class WeChatController {
@Value("${weixin.appid}")
private String appId;
@Value("${weixin.secret}")
private String secret;
/**
* 网页授权
* 通过code换取网页授权access_token(该AccessToken与基础AccessToken不一样)
*/
public final static String WEB_GET_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
/**
* 网页授权
* 获取用户详细信息(scope为 snsapi_userinfo)
*/
public final static String WEB_GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
/**
* 网页授权
* 通过code获取微信个人信息
*/
@RequestMapping(value = "/getWxInfoByCode",method = {RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public R getWxInfoByCode(@RequestParam(value = "code") String code){
JSONObject resultObj = null;
String url = WEB_GET_ACCESS_TOKEN.replace("APPID", appId).replace("SECRET", secret).replace("CODE", code);
JSONObject accessTokenObj = getJsonData(url);
if(accessTokenObj != null && accessTokenObj.get("access_token") != null ){
String accessToken = accessTokenObj.getString("access_token");
String openId = accessTokenObj.getString("openid");
if(accessToken != null){
String webGetUserInfoUrl = WEB_GET_USER_INFO.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
resultObj = getJsonData(webGetUserInfoUrl);
}
}
return R.successData(resultObj);
}
/**
* 发起get请求
* @param url
* @return
*/
public JSONObject getJsonData(String url) {
RestTemplate restTemplate = new RestTemplate();
// 设置 HTTP 头部信息
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Accept-Charset", "UTF-8");
// 创建 StringHttpMessageConverter 并设置编码方式为 UTF-8
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
stringHttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
restTemplate.getMessageConverters().add(0, stringHttpMessageConverter);
// 发送 GET 请求,并将响应映射为 JSONObject
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
// 获取响应中的 JSONObject
JSONObject jsonObject = JSONObject.parseObject(responseEntity.getBody());
return jsonObject;
}
}
R.java
响应类
package com.lc.wxtoken.business.entity;
import com.alibaba.fastjson.JSON;
/**
* 返回对象
*
* @author ASUS
*/
public class R {
/**
* 成功的编码
*/
public static final int CODE_SUCCESS = 10001;
/**
* 失败的编码
*/
public static int CODE_FAIL = 10002;
/**
* 微信未授权的错误编码
*/
public static int WECHAT_FAIL = 10004;
/**
* 执行成功的消息
*/
public static String MSG_SUCCESS = "执行成功!";
/**
* 执行失败的消息
*/
public static String MSG_FAIL = "执行失败!";
/**
* 编码
*/
public int code;
/**
* 数据
*/
public Object data;
/**
* 消息
*/
public String msg;
public R() {
}
public R(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
/**
* 默认成功返回
*
* @return
*/
public static R success() {
return new R(CODE_SUCCESS, MSG_SUCCESS, null);
}
/**
* 微信未授权返回
* @return
*/
public static R wechatNo(Object data) {return new R(WECHAT_FAIL,"未授权",data);}
/**
* 默认失败返回
*
* @return
*/
public static R fail() {
return new R(CODE_FAIL, MSG_FAIL, null);
}
/**
* 成功返回,附带数据
*
* @return
*/
public static R successData(Object data) {
return new R(CODE_SUCCESS, MSG_SUCCESS, data);
}
/**
* 失败返回,附带消息
*
* @return
*/
public static R failMsg(String msg) {
return new R(CODE_FAIL, msg, null);
}
/**
* 成功返回
*
* @param data
* @return
*/
public static String successResultObj(Object data) {
return JSON.toJSONString(new R(R.CODE_SUCCESS, R.MSG_SUCCESS, data));
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
代码地址
其中demo3
部分