国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

微信公眾號開發(fā)—掃描二維碼實(shí)現(xiàn)登錄方案

這篇具有很好參考價(jià)值的文章主要介紹了微信公眾號開發(fā)—掃描二維碼實(shí)現(xiàn)登錄方案。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

?? @ 作者: 一恍過去
?? @ 主頁: https://blog.csdn.net/zhuocailing3390
?? @ 社區(qū): Java技術(shù)棧交流
?? @ 主題: 微信公眾號開發(fā)—掃描二維碼實(shí)現(xiàn)登錄方案
?? @ 創(chuàng)作時(shí)間: 2022年12月21日

微信公眾號掃碼登錄開發(fā),開發(fā)技巧,微信公眾號開發(fā),微信,前端,微信掃碼登錄

1、準(zhǔn)備工作

1、調(diào)用微信公眾號接口,需要實(shí)現(xiàn)獲取AccessToken,參考《獲取AccessToken接口調(diào)用憑據(jù)》
2、在本地進(jìn)行聯(lián)調(diào)時(shí),為讓微信端能夠訪問到本地服務(wù),需要進(jìn)行內(nèi)網(wǎng)穿透,參考《本地服務(wù)器內(nèi)網(wǎng)穿透實(shí)現(xiàn)(NATAPP)》
3、配置微信接口配置信息,用于告訴微信接收消息的回調(diào)地址
微信公眾號掃碼登錄開發(fā),開發(fā)技巧,微信公眾號開發(fā),微信,前端,微信掃碼登錄

2、二維碼掃碼登錄說明

  • 前端調(diào)用接口,后端生成二維碼以及一個(gè)loginId參數(shù)(就是一個(gè)微信掃碼場景值 sceneStr,loginId存入redis中,時(shí)效為5分鐘);
  • 同時(shí)前端通過loginId進(jìn)行輪詢訪問判斷是否成功登錄
    • 如果掃碼后,用戶沒有進(jìn)行任何綁定,則直接回復(fù)用戶消息并且附帶上進(jìn)行綁定的引導(dǎo)鏈接(綁定操作就是一個(gè)前端頁面,進(jìn)入頁面后用戶需要同意微信網(wǎng)頁授權(quán)、并且輸入手機(jī)號、短信驗(yàn)證碼,后端將授權(quán)后得到的code查詢到openId,最后將手機(jī)號與openId進(jìn)行綁定),綁定操作參考《微信網(wǎng)頁授權(quán)自動登錄業(yè)務(wù)系統(tǒng)》;
    • 如果掃碼后,loginId已過期則要求用戶重新刷新二維碼,并且只要是授權(quán)不成功都需要重新刷新二維碼再次執(zhí)行授權(quán)流程;
    • 如果掃碼后 發(fā)現(xiàn)以及已經(jīng)綁定了openid則授權(quán)登錄成功,將用戶信息及token信息通過輪詢接口返回到前端,并且刪除loginId值;

3、yaml配置

wx:
  # 來源于測試平臺
  appid: wx79ec4331f29311b9
  secret: 1c79a199560f94096f26b8caa2a73a08
  apiUrl: https://api.weixin.qq.com/
  openApiUrl: https://open.weixin.qq.com/
  authRedirectUri: http://6uks3d.natappfree.cc/wechat/auth

4、定義工具類

MapUtils:

public class MapUtils {

    /**
     * Map轉(zhuǎn)換為 Entity
     *
     * @param params 包含參數(shù)的Map
     * @param t      需要賦值的實(shí)體
     * @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("屬性設(shè)置失?。?);
        }
        return t;
    }

    /**
     * 將對象轉(zhuǎn)換為HashMap
     *
     * @param t   轉(zhuǎn)換為Map的對象
     * @param <T> 轉(zhuǎn)換為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參數(shù)轉(zhuǎn)換為字符串
     *
     * @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對象轉(zhuǎn)換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);
    }

}

微信公眾號掃碼登錄開發(fā),開發(fā)技巧,微信公眾號開發(fā),微信,前端,微信掃碼登錄

5、掃描帶參數(shù)二維碼事件

@Service
@Slf4j
public class MessageService {
    @Resource
    private ScanAuthService scanAuthService;
    
    public String receiveAndResponseMessage(HttpServletRequest request) {
    	log.info("------------微信消息開始處理-------------");
        try {
            // 調(diào)用消息工具類MessageUtil解析微信發(fā)來的xml格式的消息,解析的結(jié)果放在HashMap里;
            Map<String, String> map = WeixinMessageUtil.xmlToMap(request);
            String jsonString = JSON.toJSONString(map);

            // 發(fā)送方賬號(用戶方)
            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_為前綴,后面為二維碼的參數(shù)值
                 String eventKey = map.get("EventKey");
                 String openId = message.getFromUserName();
                 // 進(jìn)行后續(xù)的授權(quán)處理
                 if (!StringUtils.isEmpty(eventKey)) {
                    scanAuthService.getAuth(openId, eventKey);
                 }
             }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("系統(tǒng)出錯");
            return null;
        }
    }
}

6、掃碼登錄流程示例代碼

掃碼請求實(shí)體類定義:

@Data
public class QrCodeRep {
    /**
     * 該二維碼有效時(shí)間,以秒為單位。 最大不超過2592000(即30天),此字段如果不填,則默認(rèn)有效期為60秒
     */
    private Integer expire_seconds;

    /**
     * 二維碼類型
     * QR_SCENE為臨時(shí)的整型參數(shù)值,QR_STR_SCENE為臨時(shí)的字符串參數(shù)值
     * QR_LIMIT_SCENE為永久的整型參數(shù)值,QR_LIMIT_STR_SCENE為永久的字符串參數(shù)值
     */
    private String action_name;

    /**
     * 二維碼詳細(xì)信息
     */
    private ActionInfo action_info;

    @Data
    public static class ActionInfo {
        private Scene scene;
    }

    @Data
    public static class Scene {
        /**
         * 場景值ID(字符串形式的ID),字符串類型,長度限制為1到64
         */
        private String scene_str;
    }
}

掃碼請求響應(yīng)類定義:

@Data
public class QrCodeRes {
    /**
     * 獲取的二維碼ticket,憑借此 ticket 可以在有效時(shí)間內(nèi)換取二維碼。
     */
    private String ticket;

    /**
     * 通過ticket換取的二維碼
     */
    private String ticketUrl;

    /**
     * 該二維碼有效時(shí)間,以秒為單位。 最大不超過2592000(即30天)
     */
    private Integer expire_seconds;

    /**
     * 二維碼圖片解析后的地址,開發(fā)者可根據(jù)該地址自行生成需要的二維碼圖片
     */
    private String url;

    /**
     * 場景值ID(字符串形式的ID),字符串類型,長度限制為1到64
     */
    private String sceneStr;
}

Service層:

@Slf4j
@Service
public class ScanAuthService {

    @Resource
    private WeChantService weChantService;

    @Resource
    private RestHttpRequest restHttpRequest;

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private WxBean wxBean;

    public String getAuth(String openId, String loginId) {
        String msg = "掃碼登錄成功!";

        // 如果掃碼后,loginId已過期則要求用戶重新刷新二維碼,并且只要授權(quán)不成功都需要重新刷新二維碼再次執(zhí)行授權(quán)流程
        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) {
                // 如果掃碼后,如果沒有進(jìn)行任何綁定,則直接回復(fù)用戶消息并且附帶上進(jìn)行綁定的鏈接
                msg = "<a href =\"https://www.baidu.com/\">請前往綁定</a>";
                RedisUtils.del(loginId);
            }

            // 如果掃碼后 發(fā)現(xiàn)以及已經(jīng)綁定了openid則授權(quán)登錄成功,將用戶信息及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();
        // 設(shè)置場景值
        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.weixin.qq.com/cgi-bin/showqrcode?ticket=" + URLEncoder.encode(ticket, "UTF-8");
            res.setTicketUrl(ticketUrl);
        } catch (
                UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        // 將狀態(tài)寫入redis
        ScanStatusAuthRes 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) {
            // 刪除key
            RedisUtils.del(loginId);
        }
        return ResultUtils.success(authRes);
    }
}

Controller層:

@Slf4j
@RestController
public class ScanAuthController {

    @Resource
    private ScanAuthService scanAuthService;


    /**
     * 獲取掃碼登錄二維碼
     *
     * @return
     */
    @ApiOperation(value = "獲取掃碼登錄二維碼", notes = "獲取掃碼登錄二維碼")
    @GetMapping("/scanLogin")
    public PageResult qrcodeCreate() {
        return ResultUtils.success(scanAuthService.qrcodeCreate());
    }


    /**
     * 輪詢獲取登錄狀態(tài)
     *
     * @param loginId
     * @return
     */
    @ApiOperation(value = "輪詢獲取登錄狀態(tài)", notes = "輪詢獲取登錄狀態(tài)")
    @GetMapping("/scanStatus")
    public PageResult scanStatus(@RequestParam("loginId") String loginId) {
        return ResultUtils.success(scanAuthService.scanStatus(loginId));
    }
}

微信公眾號掃碼登錄開發(fā),開發(fā)技巧,微信公眾號開發(fā),微信,前端,微信掃碼登錄文章來源地址http://www.zghlxwxcb.cn/news/detail-632162.html

到了這里,關(guān)于微信公眾號開發(fā)—掃描二維碼實(shí)現(xiàn)登錄方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包