700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 微信公众号开发—扫描二维码实现登录方案

微信公众号开发—扫描二维码实现登录方案

时间:2021-09-15 02:35:34

相关推荐

微信公众号开发—扫描二维码实现登录方案

😊 @ 作者: 一恍过去💖 @ 主页: /zhuocailing3390🎊 @ 社区: Java技术栈交流🎉 @ 主题: 微信公众号开发—扫描二维码实现登录方案⏱️ @ 创作时间: 12月21日

目录

1、准备工作2、二维码扫码登录说明3、yaml配置4、定义工具类5、扫描带参数二维码事件6、扫码登录流程示例代码

1、准备工作

1、调用微信公众号接口,需要实现获取AccessToken,参考《获取AccessToken接口调用凭据》

2、在本地进行联调时,为让微信端能够访问到本地服务,需要进行内网穿透,参考《本地服务器内网穿透实现(NATAPP)》

3、配置微信接口配置信息,用于告诉微信接收消息的回调地址

2、二维码扫码登录说明

前端调用接口,后端生成二维码以及一个loginId参数(就是一个微信扫码场景值 sceneStr,loginId存入redis中,时效为5分钟);同时前端通过loginId进行轮询访问判断是否成功登录 如果扫码后,用户没有进行任何绑定,则直接回复用户消息并且附带上进行绑定的引导链接(绑定操作就是一个前端页面,进入页面后用户需要同意微信网页授权、并且输入手机号、短信验证码,后端将授权后得到的code查询到openId,最后将手机号与openId进行绑定),绑定操作参考《微信网页授权自动登录业务系统》;如果扫码后,loginId已过期则要求用户重新刷新二维码,并且只要是授权不成功都需要重新刷新二维码再次执行授权流程;如果扫码后 发现以及已经绑定了openid则授权登录成功,将用户信息及token信息通过轮询接口返回到前端,并且删除loginId值;

3、yaml配置

wx:# 来源于测试平台appid: wx79ec4331f29311b9secret: 1c79a199560f94096f26b8caa2a73a08apiUrl: https://api./openApiUrl: https://open./authRedirectUri: /wechat/auth

4、定义工具类

MapUtils:

public class MapUtils {/*** Map转换为 Entity** @param params 包含参数的Map* @param t需要赋值的实体* @param <T> 类型*/public static <T> T mapToEntity(Map<String, Object> params, T t) {if (null == params) {return t;}Class<?> clazz = t.getClass();Field[] declaredFields = clazz.getDeclaredFields();try {for (Field declaredField : declaredFields) {declaredField.setAccessible(true);String name = declaredField.getName();if (null != params.get(name)) {declaredField.set(t, params.get(name));}}} catch (Exception e) {throw new RuntimeException("属性设置失败!");}return t;}/*** 将对象转换为HashMap** @param t 转换为Map的对象* @param <T> 转换为Map的类* @return Map*/public static <T> Map<String, Object> entityToMap(T t) {Class<?> clazz = t.getClass();List<Field> allField = getAllField(clazz);Map<String, Object> hashMap = new LinkedHashMap<>(allField.size());try {for (Field declaredField : allField) {declaredField.setAccessible(true);Object o = declaredField.get(t);if (null != o) {hashMap.put(declaredField.getName(), o);}}} catch (Exception e) {throw new RuntimeException("属性获取失败!");}return hashMap;}/*** 获取所有属性** @param clazz class* @param <T> 泛型* @return List<Field>*/public static <T> List<Field> getAllField(Class<T> clazz) {List<Field> fields = new ArrayList<>();Class<?> superClazz = clazz;while (null != superClazz) {fields.addAll(Arrays.asList(superClazz.getDeclaredFields()));superClazz = superClazz.getSuperclass();}return fields;}/*** 将Map参数转换为字符串** @param map* @return*/public static String mapToString(Map<String, Object> map) {StringBuffer sb = new StringBuffer();map.forEach((key, value) -> {sb.append(key).append("=").append(value.toString()).append("&");});String str = sb.toString();str = str.substring(0, str.length() - 1);return str;}/*** 将Bean对象转换Url请求的字符串** @param t* @param <T>* @return*/public static <T> String getUrlByBean(T t) {String pre = "?";Map<String, Object> map = entityToMap(t);return pre + mapToString(map);}}

5、扫描带参数二维码事件

@Service@Slf4jpublic class MessageService {@Resourceprivate ScanAuthService scanAuthService;public String receiveAndResponseMessage(HttpServletRequest request) {log.info("------------微信消息开始处理-------------");try {// 调用消息工具类MessageUtil解析微信发来的xml格式的消息,解析的结果放在HashMap里;Map<String, String> map = WeixinMessageUtil.xmlToMap(request);String jsonString = JSON.toJSONString(map);// 发送方账号(用户方)String fromUserName = map.get("FromUserName");// 接受方账号(公众号)String toUserName = map.get("ToUserName");// 消息类型String msgType = map.get("MsgType");log.info("fromUserName is:" + fromUserName + " toUserName is:" + toUserName + " msgType is:" + msgType);// 事件类型String eventType = map.get("Event");if (eventType.equals(MessageType.EVENT_TYPE_SCAN)) {BaseEvent message = JSON.parseObject(jsonString, BaseEvent.class);log.info("扫码成功 {}", message);// 事件 KEY 值,qrscene_为前缀,后面为二维码的参数值String eventKey = map.get("EventKey");String openId = message.getFromUserName();// 进行后续的授权处理if (!StringUtils.isEmpty(eventKey)) {scanAuthService.getAuth(openId, eventKey);}}} catch (Exception e) {e.printStackTrace();log.error("系统出错");return null;}}}

6、扫码登录流程示例代码

扫码请求实体类定义:

@Datapublic class QrCodeRep {/*** 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒*/private Integer expire_seconds;/*** 二维码类型* QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值* QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值*/private String action_name;/*** 二维码详细信息*/private ActionInfo action_info;@Datapublic static class ActionInfo {private Scene scene;}@Datapublic static class Scene {/*** 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64*/private String scene_str;}}

扫码请求响应类定义:

@Datapublic class QrCodeRes {/*** 获取的二维码ticket,凭借此 ticket 可以在有效时间内换取二维码。*/private String ticket;/*** 通过ticket换取的二维码*/private String ticketUrl;/*** 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天)*/private Integer expire_seconds;/*** 二维码图片解析后的地址,开发者可根据该地址自行生成需要的二维码图片*/private String url;/*** 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64*/private String sceneStr;}

Service层:

@Slf4j@Servicepublic class ScanAuthService {@Resourceprivate WeChantService weChantService;@Resourceprivate RestHttpRequest restHttpRequest;@Resourceprivate UserInfoMapper userInfoMapper;@Resourceprivate WxBean wxBean;public String getAuth(String openId, String loginId) {String msg = "扫码登录成功!";// 如果扫码后,loginId已过期则要求用户重新刷新二维码,并且只要授权不成功都需要重新刷新二维码再次执行授权流程if (!RedisUtils.hasKey(loginId)) {msg = "扫码登录已过期,请重新刷新二维码!";}Object o = RedisUtils.get(loginId);if (o == null) {msg = "扫码登录已过期,请重新刷新二维码!";} else {ScanStatusAuthRes authRes = JSON.parseObject(o.toString(), ScanStatusAuthRes.class);UserInfo userInfo = userInfoMapper.selectByOpenId(openId);if (userInfo == null) {// 如果扫码后,如果没有进行任何绑定,则直接回复用户消息并且附带上进行绑定的链接msg = "<a href =\"/\">请前往绑定</a>";RedisUtils.del(loginId);}// 如果扫码后 发现以及已经绑定了openid则授权登录成功,将用户信息及token信息通过轮询接口返回到前端,并且删除loginId值authRes.setStatus(2);authRes.setUserInfo(userInfo);long expire = RedisUtils.getExpire(loginId);RedisUtils.setEx(loginId, JSON.toJSONString(authRes), expire, TimeUnit.SECONDS);}return msg;}public PageResult qrcodeCreate() {String url = wxBean.getApiUrl() + InterfaceConstant.QR_CODE_CREATE;BaseRep rep = new BaseRep();rep.setAccess_token(weChantService.getAccessToken());url = url + MapUtils.getUrlByBean(rep);QrCodeRep codeRep = new QrCodeRep();codeRep.setAction_name("QR_STR_SCENE");codeRep.setExpire_seconds(5 * 60);QrCodeRep.ActionInfo actionInfo = new QrCodeRep.ActionInfo();QrCodeRep.Scene scene = new QrCodeRep.Scene();// 设置场景值String loginId = UUIDUtils.getUuId();scene.setScene_str(loginId);actionInfo.setScene(scene);codeRep.setAction_info(actionInfo);Map map = restHttpRequest.doHttp(url, HttpMethod.POST, codeRep);QrCodeRes res = new QrCodeRes();MapUtils.mapToEntity(map, res);res.setSceneStr(scene.getScene_str());try {// 通过ticket获取二维码String ticket = res.getTicket();String ticketUrl = "https://mp./cgi-bin/showqrcode?ticket=" + URLEncoder.encode(ticket, "UTF-8");res.setTicketUrl(ticketUrl);} catch (UnsupportedEncodingException e) {e.printStackTrace();}// 将状态写入redisScanStatusAuthRes authRes = new ScanStatusAuthRes();authRes.setStatus(1);RedisUtils.setEx(loginId, JSON.toJSONString(authRes), res.getExpire_seconds(), TimeUnit.SECONDS);return ResultUtils.success(res);}public PageResult scanStatus(String loginId) {// 通过redis查询是否存在if (!RedisUtils.hasKey(loginId)) {return ResultUtils.fail("扫码登录已过期,请重新刷新二维码!");}Object o = RedisUtils.get(loginId);ScanStatusAuthRes authRes = JSON.parseObject(o.toString(), ScanStatusAuthRes.class);if (authRes.getStatus() == 2) {// 删除keyRedisUtils.del(loginId);}return ResultUtils.success(authRes);}}

Controller层:

@Slf4j@RestControllerpublic class ScanAuthController {@Resourceprivate ScanAuthService scanAuthService;/*** 获取扫码登录二维码** @return*/@ApiOperation(value = "获取扫码登录二维码", notes = "获取扫码登录二维码")@GetMapping("/scanLogin")public PageResult qrcodeCreate() {return ResultUtils.success(scanAuthService.qrcodeCreate());}/*** 轮询获取登录状态** @param loginId* @return*/@ApiOperation(value = "轮询获取登录状态", notes = "轮询获取登录状态")@GetMapping("/scanStatus")public PageResult scanStatus(@RequestParam("loginId") String loginId) {return ResultUtils.success(scanAuthService.scanStatus(loginId));}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。