目的1:有项目开发需要,亲自踩坑无数,网上难有合适全套的,故产出回报社会
目的2:几年了,老是白嫖不合适,出来混的总得还
目的3:处女作,凡事总会有第一次
1.流程图
2.菜单配置
菜单可直接配置为:微信鉴权路径(固定写法)+转发后的地址(转发的地址一般为前端页面)
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx77777777&redirect_uri=http%3A%2F%2F7d.natapp.cc&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
复制代码
JAVA代码如下:
/**
* 获取微信授权
* 此请求需在公众号菜单中配置,做为开始
*/
@ApiOperation("跳转至微信鉴权")
@RequestMapping("/wxLoginInit")
public void loginInt(HttpServletResponse response) throws IOException {
String APP_ID = "MP_APPID";
String BACK_URL = "BACK_URL";
//拼接地址
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
+APP_ID
+ "&redirect_uri="
+ URLEncoder.encode(BACK_URL,"UTF-8")
+ "&response_type=code"
+ "&scope=snsapi_userinfo"
+ "&state=STATE#wechat_redirect";
//重定向到重定向地址
log.info("【微信网页授权】获取code,redirectURL={}", url);
response.sendRedirect(url);
}
复制代码
注意:
1.转发后的地址必须在可信域中,必须必须必须加http://
,必须URLEncoder
2.微信公众号在网页授权域名中,要求将以下文件上传至填写域名或路径指向的web服务器(或虚拟主机)的目录
此文件必须放在前端前端前端根目录下,可拿nginx做代理,放在nginx/html目标下通过域名校验
3.获取code
前端页面拿到请求,从请求中截取拿到code
//从请求中截取code
let code = window.location.href.match(/code=(\S*)&/) ? window.location.href.match(/code=(\S*)&/)[1] : '';
复制代码
4.拿code换取所需信息
前端拿到code后再发一个请求去后台请求,便可拿到所需信息,包括openId等
WxMpService wxMpService = WxMpConfig.getWxMpService();
//根据code获取access_toke
WxMpOAuth2AccessToken accessToken = wxMpService.oauth2getAccessToken(code);
String lang = "zh_CN";
//根据access_token获取用户基本信息
WxMpUser wxMpUser = wxMpService.oauth2getUserInfo(accessToken, lang);
String openId = wxUserInfo.getOpenId();
复制代码
5.根据openId获取系统用户
根据拿到的openId去系统中查找是否有相对应的用户,如果有,可以直接登录生成token,如果没有,可以返回错误信息,让前端引导到登录注册页面
//根据openId去系统中查找用户
User byAccount = userService.getByAccount(openId);
if(ToolUtil.isNotEmpty(byAccount)){
Map returnData = new HashMap<>();
String token = authService.login(openId);
returnData.put("token", token);
returnData.put("wxUserInfo", wxUserInfo);
return ResponseData.success(returnData);
}else {
return ResponseData.error("用户未注册!");
}
复制代码
6.前端存储token
本项目为uniapp框架,其他前端类似,在拿到token后,存储到LocalStorage
uni.request({
url: 'https://www.example.com/wechat/getUserInfo', //仅为示例,并非真实接口地址。
data: {
'token': token
},
header: {
'custom-header': 'hello' //自定义请求头信息
'X-Requested-With': 'XMLHttpRequest',
"Accept": "application/json",
"Content-Type": "application/json; charset=UTF-8"
},
success: (res) => {
console.log(res.data.data.token);
this.text = 'request success';
}
});
复制代码
7.前端请求数据
所有前端请求时都从LocalStorage中取到token附加到请求头里去请求后台数据
8.完整代码
8.1 pom.xml
<!--微信公众号开发包-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>3.8.0</version>
</dependency>
复制代码
8.2 后台
@Controller
@RequestMapping("/wechat")
@Slf4j
public class WechatController {
@Autowired
private UserService userService;
@Autowired
private AuthService authService;
/**
* 获取微信授权
* 此请求需在公众号菜单中配置,做为开始
*/
@ApiOperation("跳转至微信鉴权")
@RequestMapping("/wxLoginInit")
public void loginInt(HttpServletResponse response) throws IOException {
String APP_ID = (String) ConstantsContext.getConstntsMap().get("MP_APPID");
String BACK_URL = (String) ConstantsContext.getConstntsMap().get("BACK_URL");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
+APP_ID
+ "&redirect_uri="
+ URLEncoder.encode(BACK_URL,"UTF-8")
+ "&response_type=code"
+ "&scope=snsapi_userinfo"
+ "&state=STATE#wechat_redirect";
//重定向到重定向地址
log.info("【微信网页授权】获取code,redirectURL={}", url);
response.sendRedirect(url);
}
/**
* 根据code获取个人基本信息
* @param code
* @return
* @throws Exception
*/
@PostMapping("/getUserInfo")
@ResponseBody
public ResponseData getUserInfo(String code,HttpServletResponse response) throws Exception {
WxMpService wxMpService = WxMpConfig.getWxMpService();
//根据code获取access_toke
WxMpOAuth2AccessToken accessToken = wxMpService.oauth2getAccessToken(code);
String lang = "zh_CN";
//根据access_token获取用户基本信息
WxMpUser wxUserInfo = wxMpService.oauth2getUserInfo(accessToken, lang);
String openId = wxUserInfo.getOpenId();
//根据openId去系统中查找用户
User byAccount = userService.getByAccount(openId);
if(ToolUtil.isNotEmpty(byAccount)){
Map returnData = new HashMap<>();
String token = authService.login(openId);
returnData.put("token", token);
returnData.put("wxUserInfo", wxUserInfo);
return ResponseData.success(returnData);
}else {
return ResponseData.error("用户未注册!");
}
}
}
复制代码
8.3前端(uniapp)
封装请求api.js
const baseUrl = 'localhost:17000';
/**
* 普通请求
*/
const httpRequest = (opts, data) => {
let httpDefaultOpts = {
url: baseUrl + opts.url,
data: data,
method: opts.method,
header: opts.method == 'get' ? {
'X-Requested-With': 'XMLHttpRequest',
"Accept": "application/json",
"Content-Type": "application/json; charset=UTF-8"
} : {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
dataType: 'json',
}
let promise = new Promise(function(resolve, reject) {
uni.request(httpDefaultOpts).then(
(res) => {
resolve(res[1])
}
).catch(
(response) => {
reject(response)
}
)
})
return promise
};
/**
* 带Token请求
*/
const httpTokenRequest = (opts, data) => {
let token = "";
uni.getStorage({
key: 'token',
success: function(ress) {
token = ress.data
}
});
//此token是登录成功后后台返回保存在storage中的
let httpDefaultOpts = {
url: baseUrl + opts.url,
data: data,
method: opts.method,
header: opts.method == 'get' ? {
'Authorization': token,
'X-Requested-With': 'XMLHttpRequest',
"Accept": "application/json",
"Content-Type": "application/json; charset=UTF-8"
} : {
'Authorization': token,
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
dataType: 'json',
}
let promise = new Promise(function(resolve, reject) {
uni.request(httpDefaultOpts).then(
(res) => {
resolve(res[1])
}
).catch(
(response) => {
reject(response)
}
)
})
return promise
};
export default {
baseUrl,
httpRequest,
httpTokenRequest
}
复制代码
App.vue
<script>
export default {
onLaunch: function() {
const wxUserInfo = uni.getStorageSync('wxUserInfo');
if (!wxUserInfo) {
console.log('请求个人信息!');
//从请求中截取code
let code = window.location.href.match(/code=(\S*)&/) ? window.location.href.match(/code=(\S*)&/)[1] :
'';
if (code) {
let opts = {
url: '/wechat/getUserInfo',
method: 'POST'
};
let param = {
"code": code
};
this.$myRequest.httpTokenRequest(opts, param).then(
res => {
let token = res.data.data.token;
let wxUserInfo = res.data.data.wxUserInfo;
uni.setStorageSync('wxUserInfo', wxUserInfo);
uni.setStorageSync('token', token);
},
error => {
uni.navigateTo({
url: "pages/register/register"
})
}
)
} else {
console.error("code获取失败!!!");
uni.navigateTo({
url: "pages/register/register"
})
}
} else {
console.log("正常在线");
}
}
}
</script>
<style>
/*每个页面公共css */
</style>
复制代码
main.js
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
App.mpType = 'app'
import myRequest from './pages/base/api.js';
Vue.prototype.$myRequest = myRequest;
const app = new Vue({
...App
})
app.$mount()
复制代码
最后感谢掘金这个平台,真心不错
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END