代码可复制,直接使用
官方文档:详细看很重要
地址:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
官方给的时序图进行简单的分析
1.当小程序调用wx.login()时,会获得一个code(临时登录凭证),然后我们需要用wx.request()将code发送到自己的服务器.
2.在服务器的接口中,调用登录凭证校检接口,将appid(小程序唯一标识)+appsecret(小程序的app secret)+code发送到微信接口服务.然后微信服务器会返回session_key(会话秘钥)+openid(用户的唯一标识).
3.在服务器的接口中,已经得到微信用户的唯一标识openid,已经数据传输的session_key,接下来就写业务逻辑了.
4.返回给小程序自定义登录态,小程序将它存入storage中.接下来的wx.request()的业务请求,都会携带自定义登录态.
5.在服务器的接口中通过自定义登录态查询openid和session_key,然后返回业务数据
在服务器的接口中,需要进行一个http请求,将从小程序获得的code和申请小程序时自己的appid和secret这三个参数发送给微信接口服务,然后就可以获得session_key和openid,就是通过下边的接口获取
查看官方文档要获取openid和session_key 最主要的是微信提供的接口:
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
说这么多 ,直接上代码:
小程序登录示例代码aap.js中写,因为登录需要全局:
//app.js
App({
onLaunch: function (options) {
this.globalData.userInfo = wx.getStorageSync('userInfo');//获取用户信息==缓存
this.globalData.currentCity = wx.getStorageSync('currentCity');//获取用城市坐标==缓存
var member = wx.getStorageSync('member');
console.log('app member', member);
console.log('app userInfo', this.globalData.userInfo);
this.globalData.member = member;
//调用
this.userRegister();
var that = this;
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
that.globalData.userInfo = res.userInfo
console.log('userInfo: ',res.userInfo);
wx.setStorageSync('userInfo', res.userInfo);
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (that.userInfoReadyCallback) {
that.userInfoReadyCallback(res)
}
}
})
}
}
})
},
userRegister: function () {
var that = this;
wx.login({
success: res => {
console.log("用户登录凭证 code: " + res.code);
wx.request({
url: 'http://localhost:8081/WxMiniapp/WeChatLogin/login',//测试接口
data: { code: res.code, Nickname: '游客' },
header: { 'content-type': 'application/json;' },
success: res => {
console.log('resultCode:' + res.data.resultCode);
if (res.data.resultCode == '0') {
wx.setStorageSync("member", res.data.member);
wx.setStorageSync("session_key", res.data.session_key);
console.log(res.data, ' first page')
that.globalData.member = res.data.member;
console.log('缓存中member: ', wx.getStorageSync('member'));
} else {
wx.showToast({
title: res.data.msg,
mask: true,
icon: 'none',
duration: 1500
})
}
},
fail: res => {
console.log('register failed');
}
})
}
})
},
globalData: {
userInfo: null,
member:''
}
})
java后台代码:
package com.mtx.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import com.google.gson.Gson;
import com.mtx.bean.table.CodeToUser;
import com.mtx.bean.table.Mem_member;
import com.mtx.service.MemberService;
@Controller
@RequestMapping(value="/WeChatLogin")
public class WeChatLogin{
private static Logger log = Logger.getLogger(WeChatLogin.class);
@Autowired
private MemberService memberService;
private static final String APPID = "你的appid";
private static final String SECRET = "你的SECRET ";
@RequestMapping(value="/login")
//获取凭证校检接口
public @ResponseBody Object login(Mem_member member,HttpServletRequest request,HttpServletResponse response) throws Exception{
Map<String, Object> resMap = new HashMap<String, Object>();
boolean flag=false;
String code = request.getParameter("code");//用户登录的code用于获取openid
//微信的接口
String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+APPID+
"&secret="+SECRET+"&js_code="+ code +"&grant_type=authorization_code";
RestTemplate restTemplate = new RestTemplate();
//进行网络请求,访问url接口
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
//根据返回值进行后续操作
System.out.println(responseEntity);
if(responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK){
String sessionData = responseEntity.getBody();
Gson gson = new Gson();
//解析从微信服务器获得的openid和session_key;
CodeToUser codeuser = gson.fromJson(sessionData,CodeToUser.class);
member.setOpenid(codeuser.getOpenid());
int count = memberService.getMemberByInfo(member);//判断用户是否已注册
if(count==0){
try {
flag = memberService.insertMember(member);
} catch (Exception e) {
flag = false;
resMap.put("resultCode", "1");
log.error("会员信息注册失败:"+e.toString());
e.printStackTrace();
}
}else{
flag = true;
}
resMap.put("session_key", codeuser.getSession_key());
}else{
resMap.put("msg","未获取到用户唯一标识");
resMap.put("resultCode", "10002");
return resMap;
}
//返回会员信息
if(flag){
Mem_member mem = memberService.getMember(member.getOpenid());
resMap.put("member",mem);
resMap.put("resultCode", "0");
}else{
resMap.put("resultCode", "1");
log.info("会员信息注册失败");
}
return resMap;
}
}
用于自定义登录状态与相关:
1:CodeToUser接收oppid和session_key实体类:
package com.mtx.bean.table;
public class CodeToUser {
private String openid;//用户openid
private String session_key;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getSession_key() {
return session_key;
}
public void setSession_key(String session_key) {
this.session_key = session_key;
}
}
2:Mem_member 用户信息的实体类:
package com.mtx.bean.table;
import java.util.List;
import com.mtx.dao.annotation.Id;
import com.mtx.dao.annotation.Table;
@Table(value="mem_member")
public class Mem_member {
@Id
private String memberno;//会员号
private String Nickname;//昵称
private String mobile;//电话号
private String createdate;//注册时间
private String openid;
private String placeno;//影院编码
public String getMemberno() {
return memberno;
}
public void setMemberno(String memberno) {
this.memberno = memberno;
}
public String getNickname() {
return Nickname;
}
public void setNickname(String nickname) {
Nickname = nickname;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getCreatedate() {
return createdate;
}
public void setCreatedate(String createdate) {
this.createdate = createdate;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getPlaceno() {
return placeno;
}
public void setPlaceno(String placeno) {
this.placeno = placeno;
}
@Override
public String toString() {
return "Mem_member [memberno=" + memberno + ", Nickname=" + Nickname
+ ", mobile=" + mobile + ", createdate=" + createdate
+ ", openid=" + openid + ", placeno=" + placeno + "]";
}
}
service层:判断用户是否已注册:
/**判断用户是否已注册
* 根据手机号或openid判断用户是否存在
* @param mobile
* @return
* @throws Exception
*/
public int getMemberByInfo(Mem_member member)throws Exception;
serviceImpl层:判断用户是否已注册:
/** 判断用户是否已注册
* 根据手机号 或openid获取用户信息
*/
@Override
public int getMemberByInfo(Mem_member member) throws Exception {
String sql = "select count(m.openid) from mem_member m where 1=1";
int count=0;
if (!StringUtils.isEmpty(member.getOpenid())) {
sql+=" and m.openid=?";
count = dao.getCount(sql, new Object[]{member.getOpenid()});
}else{
sql+=" and m.mobile=?";
count = dao.getCount(sql, new Object[]{member.getMobile()});
}
System.out.println(sql);
return count;
}
service层:新增会员信息:
/**
* 新增会员信息
* @param member
* @return
* @throws Exception
*/
public boolean insertMember(Mem_member member)throws Exception;
serviceImpl层:
/**
* 会员注册
*/
@Override
@Transactional
public boolean insertMember(Mem_member member) throws Exception {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
member.setCreatedate(df.format(new Date()));
String insertSql = "insert into mem_member (nickname,mobile,createdate,openid) values(?,?,?,?)";
return dao.insertsql(insertSql, new Object[]{member.getNickname(),member.getMobile(),member.getCreatedate(),member.getOpenid()});
}
dao层我是封装的 请大家自己完成
小程序控制台效果:
后台输出效果: