1. HTTP3W博客首页
  2. Java

uniapp实现小程序登录(支持手机号授权登录)

第一步.前端处理

页面登录按钮

<!--第一种:手机号授权登录-->
<button size="lg" class="white br60 row-center btn"  open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
<image class="mr10 image" src="/static/images/icon_wechat.png"></image>
<text>微信一键授权</text>
</button> 

<!-- 第二种:微信用户授权登录 -->
			<!-- <button size="lg" class="white br60 row-center btn" @click="mnpLoginFun">
				<image class="mr10 image" src="/static/images/icon_wechat.png"></image>
				<text>微信授权登录</text>
			</button> -->

js函数,调用后台接口,实现登录

import { getWxCode } from '@/utils/login';
	methods: {
		//...mapMutations(['LOGIN']),
//小程序微信手机号授权登录
	async getPhoneNumber(e) {
			if (e.detail.errMsg == 'getPhoneNumber:fail user deny') {
				console.log('用户拒绝提供手机号');
			} else {
				uni.showLoading({
					title: '登录中...',
					mask: true
				});
				const wxCode = await getWxCode();
				uni.request({
					url: baseURL + '/mobile-api/wechat/getWxOpenIdAndSkey',
					header: {
						'content-type': 'application/x-www-form-urlencoded'
					},
					method: 'POST',
					data: {
						code: wxCode,
						encryptedData: e.detail.encryptedData,
						iv: e.detail.iv
					},
					success: res => {
                                              //登录成功后,业务处理
						console.log("res::",res)
						if(res.data.code == 1) {
                                                       //前端处理用户登录信息
							this.loginHandle(res.data.data)
                                                       //登录成功跳转页面
							uni.switchTab({
								url:"/pages/index/index"
							})
						}else {
							this.$toast({
								title: "服务异常"
							})
						}
					}
				});
				
			}
		},
//小程序微信用户授权登录
async mnpLoginFun() {
			const userInfo = await getUserProfile();
			console.log(userInfo, 'userInfo');
			uni.showLoading({
				title: '登录中...',
				mask: true
			});
			const wxCode = await getWxCode();
			uni.request({
				url: baseURL + '/mobile-api/wechat/getWxOpenIdAndSkey',
				header: {
					'content-type': 'application/x-www-form-urlencoded'
				},
				method: 'POST',
				data: {
					code: wxCode,
					encryptedData: userInfo.encryptedData,
					iv: userInfo.iv
				},
				success: res => {
					if(res.data.code == 1) {
						this.loginHandle(res.data.data)
						uni.switchTab({
							url:"/pages/index/index"
						})
					}else {
						this.$toast({
							title: "服务异常"
						})
					}
				}
			});
                },
// 登录结果处理
		async loginHandle(data) {
			//this.LOGIN(data);
			uni.hideLoading();
		}

js函数,获取登录凭证(code), 本例文件目录 /utils/login.js

// 获取登录凭证(code)
export function getWxCode() {
	return new Promise((resolve, reject) => {
		uni.login({
			provider: 'weixin',
			success(res) {
				resolve(res.code);
			},

			fail(res) {
				reject(res);
			}

		});
	});
}

拓展,可忽略import Cache from ‘@/utils/cache’;

const Cache = {
	//设置缓存(expire为缓存时效)
	set(key, value, expire) {
		
		let data = {
			expire: expire ? (this.time() + expire) : "",
			value
		}
		
		console.log(data, key)
		if (typeof data === 'object')
			data = JSON.stringify(data);
		try {
			uni.setStorageSync(key, data)
		} catch (e) {
			return false;
		}
	},
	get(key) {
		try {
			let data = uni.getStorageSync(key)
			const {value, expire} = JSON.parse(data)
			if(expire && expire < this.time()) {
				uni.removeStorageSync(key)
				return false;
			}else {
				return value
			}
		} catch (e) {
			return false;
		}
	},
	//获取当前时间
	time() {
		return Math.round(new Date() / 1000);
	},
	remove(key) {
		if(key) uni.removeStorageSync(key)
	}
}

export default Cache;

第二步.Java后端处理

登录接口,入口

   @RequestMapping(value = "getWxOpenIdAndSkey",method = RequestMethod.POST)
    public  Object getWxOpenIdAndSkey(String code, String iv,String encryptedData, HttpServletRequest request) {
        try{
            Map<String,Object> map = weixinService.getWxOpenIdAndSkey(code);
            String openid = map.get("openid").toString();
            ShopUser user = shopUserService.findByWechatOpenId(openid);
            JSONObject obj = getUserInfo(encryptedData, map.get("session_key").toString(), iv);

            if(obj!=null){
                if(obj.containsKey("avatarUrl")) {
                   //获取头像
                }
                if(obj.containsKey("nickName")) {
                 //获取昵称
                }
                //性别 0:未知、1:男、2:女
                if(obj.containsKey("gender")){
                 //获取性别
                }
                if(obj.containsKey("phoneNumber")){
                 //获取手机号
                    //user.setMobile(obj.getString("phoneNumber"));
                }

            }
           //user是用户信息接收对象,这里省略,你你懂得。。
           // map.put("user", user);

            return  Json.toJson(map);
        }catch (Exception e){
            logger.info("{}:解析用户信息异常",e);
            return Rets.failure( e.getMessage());
        }
    }
WeixinService.java(文件内容仅保留微信相关,配置参数取与数据库后台配置,这里省略)
 package cn.enilu.flash.service.api;

import cn.enilu.flash.bean.constant.CfgKey;
import cn.enilu.flash.bean.entity.shop.ShopUser;
import cn.enilu.flash.bean.entity.system.Cfg;
import cn.enilu.flash.bean.exception.ApplicationException;
import cn.enilu.flash.bean.exception.ApplicationExceptionEnum;
import cn.enilu.flash.bean.vo.shop.WechatInfo;
import cn.enilu.flash.cache.CacheDao;
import cn.enilu.flash.service.shop.ShopUserService;
import cn.enilu.flash.service.system.CfgService;
import cn.enilu.flash.utils.HttpUtil;
import cn.enilu.flash.utils.Maps;
import cn.enilu.flash.utils.StringUtil;
import org.json.JSONObject;
import org.nutz.http.Http;
import org.nutz.json.Json;
import org.nutz.mapl.Mapl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author :wt
 * @date :Created in 1/19/2020 4:31 PM
 */
@Service
public class WeixinService {
    @Autowired
    private CfgService cfgService;
    @Autowired
    private ShopUserService shopUserService;
    @Autowired
    private CacheDao cacheDao;
    private Logger logger = LoggerFactory.getLogger(WeixinService.class);



    public String getAccessToken() {
        String appId = cfgService.getCfgValue(CfgKey.WX_APP_ID);
        String appSecret = cfgService.getCfgValue(CfgKey.WX_APP_SECRET);
        String accessTokenUrl = cfgService.getCfgValue(CfgKey.WX_ACCESS_TOKEN_URL);
        String url = String.format(accessTokenUrl, appId, appSecret);
        String result = Http.get(url).getContent();
        logger.info("获取微信token,\r\nurl : {},\r\n result : {}", url, result);
        Object object = Json.fromJson(StringUtil.sNull(result));
        String access_token = (String) Mapl.cell(object, "access_token");
        return access_token;
    }


    public Map<String, Object> getPrivateAccessToken(String code) {

        String url = "https://api.weixin.qq.com/sns/jscode2session";
        url += "?appid=" + cfgService.getCfgValue(CfgKey.WX_APP_ID);
        url += "&secret=" + cfgService.getCfgValue(CfgKey.WX_APP_SECRET);
        url += "&js_code=" + code;
        url += "&grant_type=authorization_code";
        try {
            String result = Http.get(url).getContent();
            Object object = Json.fromJson(StringUtil.sNull(result));

            logger.info("url:" + url + ";  response:" + Json.toJson(object));
            //access_token
            String access_token = (String) Mapl.cell(object, "session_key");
            if (StringUtil.isNotEmpty(access_token)) {
                return (Map) object;
            }
        } catch (Exception e) {
            logger.error("获取token失败", e);
        }
        return null;
    }

    public WechatInfo getWechatInfoByCode(String code) {
        Map<String, Object> ret = getPrivateAccessToken(code);
        logger.info("获取token:{}", Json.toJson(ret));
        if (ret != null && ret.get("errcode") == null) {
            String openId = StringUtil.sNull(ret.get("openid"));
            return getWechatInfo(openId);
        }
        return null;
    }

//https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s
    public WechatInfo getWechatInfo(String openId) {
        String accessToken = cfgService.getCfgValue(CfgKey.WX_ACCESS_TOKEN);
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openId;
        String result = Http.get(url).getContent();

        Object object = Json.fromJson(StringUtil.sNull(result));

        logger.info("getWecchatInfo====url:" + url + ";  response:" + Json.toJson(object));
        if (Mapl.cell(object, "errcode") != null) {
            logger.info("获取微信用户基本信息失败", Mapl.cell(object, "errmsg"));
            if(Mapl.cell(object, "errcode").toString().equals("40001")){
                updateWeixinToken();
                getWechatInfo(openId);
            }
        } else {
            if (StringUtil.equals(StringUtil.sNull(Mapl.cell(object, "errcode")), "0")) {
                logger.error("用户:{}没有关注该公众号", openId);
            } else {
                WechatInfo wechatInfo = new WechatInfo();
                wechatInfo.setOpenId(openId);
                wechatInfo.setNickName(StringUtil.sNull(Mapl.cell(object, "nickname")));
                wechatInfo.setHeadUrl(StringUtil.sNull(Mapl.cell(object, "headimgurl")));
                return wechatInfo;
            }
        }
        return null;
    }

    private String createNonceStr() {
        return UUID.randomUUID().toString();
    }

    private String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    private String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    public Map<String, String> getSign(String url) {
        Map<String, String> map = getSign(cfgService.getCfgValue(CfgKey.WX_JS_API_TICKET), url);
        map.put("appId", cfgService.getCfgValue(CfgKey.WX_APP_ID));
        return map;
    }

    public Map<String, String> getSign(String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = createNonceStr();
        String timestamp = createTimestamp();
        String string1;
        String signature = "";

        // 注意这里参数名必须全部小写,且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "&timestamp=" + timestamp + "&url=" + url;
        logger.info(string1);
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }

    public Map<String, Object> getWxOpenIdAndSkey(String code) {
        Map<String, Object> map = getPrivateAccessToken(code);
        map.put("code",1);//自定义登录成功状态
        //return  Json.toJson(map);
        return map;
    }
}

通过以上步骤,可满足用户微信小程的登录,包括手机号授权登录,并获取用户详细登录信息.

 

有疑问的地方,欢迎大家给我留言,一起交流哦~

1、原创文章,作者:诺米,如若转载,请注明出处:https://www.http3w.com/archives/732

2、本站内容若有雷同从属巧合,若侵犯了您的权益,请联系本站删除,E-mail: wtao219@qq.com

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

联系我们

254007489

在线咨询:点击这里给我发消息

邮件:wtao219@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息