• 实现H5网页授权


    一、基本介绍

    ⭐️ H5 网页授权的核心:获取 openid(openid 是每个用户针对每个公众号都会产生的一个安全的,识别用户的,唯一标识用户的字符串)
    ⭐️ 为什么要获取用户的 openid 呢?用于唯一识别一个用户,为了让系统管理员知道是那个微信用户在系统中操作(如:是那个微信用户提交了表单)

    二、获取 openid(前端代码)

    (1) 创建一个 uniapp 项目

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    (2) 获取步骤

    官方介绍:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

    a. 介绍

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

    code: 用户临时登录凭证
    上面的链接的核心参数的介绍:
    ⭐️ ① appid: 应用的唯一标识
    ⭐️ ② redirect_uri: 获取到 code 后要访问的链接(通常是某个 Controller 接口)
    ⭐️ ③ scope: ❤️a. 如果值是 snsapi_base 表示是静默授权(系统悄悄获得用户的 openid,无需用户点击按钮)❤️ b. 如果值是 snsapi_userinfo 表示是非静默授权(系统弹框让用户点击【确定】按钮后方可获取用户的 openid)

    b. 前端代码

    在刚刚创建的 uniapp 项目的 App.vue 文件中的 onLoad(应用第一次被用户访问的时候会调用该方法) 中写如下代码

    <script>
    	export default {
    		onLaunch: function() {
    			// 用户第一次进入程序的时候自动调用 login 方法
    			this.login()
    		},
    		methods: {
    			login() {
    				const appid = 'wxebbeb8968f1c9b29'
    				const redirectUri = encodeURIComponent(BASE_NETWORK_URI + 'authOpenIds/h5')
    				const scope = 'snsapi_userinfo'
    
    				let url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=".concat(appid)
    					.concat("&redirect_uri=").concat(redirectUri).concat("&response_type=code&scope=").concat(scope)
    					.concat("&state=STATE #wechat_redirect")
    
    				// 访问
    				window.location.href = url
    			},
    		},
    	}
    </script>
    
    <style>
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    c. 后端代码

    用于获取 openid 的工具类

    public class OpenidUtil{
    
       public static final String APP_ID = "wxc436706a34c9dcd8";
       public static final String APP_SECRET = "7fe003e0a896420042307f567c58144a";
    
       // Spring 提供的发送 HTTP 请求的工具
       private static RestTemplate restTemplate = new RestTemplate();
    
       public static final String ACCESS_TOKEN = "access_token";
       public static final String EXPIRES_IN = "expires_in";
       public static final String OPEN_ID = "openid";
       public static final String REFRESH_TOKEN = "refresh_token";
       public static final String SCOPE = "scope";
    
       private static AccessTokenExpiresIn accessTokenExpiresIn;
    
       // 获取普通 access_token 的请求路径
       private static String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=gqAPPID&secret=gqAPPSECRET";
       private static String authorizeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=gqAPPID&redirect_uri=gqREDIRECT_URI&response_type=code&scope=gqSCOPE&state=gqSTATE#wechat_redirect";
       // 获取网页授权 access_token 的请求路径
       private static String authorizeTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=gqAPPID&secret=gqSECRET&code=gqCODE&grant_type=authorization_code";
       // 拉取用户信息的请求路径
       private static String getUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=gqACCESS_TOKEN&openid=gqOPENID&lang=zh_CN";
    
    
       /**
        * 通过 code 值获取网页授权 access_token、openid等
        *
        * @param code 当用户点击同意授权后可获得
        * @return 携带返回数据的 Map
        */
       public static Map<String, String> getH5OpenIdAccessTokenByCode(String code) {
           HashMap<String, String> resultMap = new HashMap<>();
    
           String url = authorizeTokenUrl.replace("gqAPPID", APP_ID)
                   .replace("gqSECRET", APP_SECRET)
                   .replace("gqCODE", code);
           String resultStr = restTemplate.getForObject(url, String.class);
           JSONObject resultJSON = JSONUtil.parseObj(resultStr);
    
           return createResultMap(resultJSON, ACCESS_TOKEN, EXPIRES_IN, REFRESH_TOKEN, OPEN_ID, SCOPE);
       }
    
       /**
        * 根据 accessToken 和 openid 获取用户信息
        *
        * @param accessToken
        * @param openid
        */
       public static Map<String, String> getUserInfoByOpenIdAccessToken(String accessToken, String openid) {
           String url = getUserInfoUrl.replace("gqACCESS_TOKEN", accessToken)
                   .replace("gqOPENID", openid);
           String userInfoStr = restTemplate.getForObject(url, String.class);
           JSONObject returnJSON = JSONUtil.parseObj(userInfoStr);
    
           HashMap<String, String> returnMap = new HashMap<>();
    
           return createResultMap(returnJSON, OPEN_ID, "sex", "language", "city", "province", "country", "headimgurl");
       }
    
    
       /**
        * 【方法】获取进入授权页面的请求路径
        *
        * @param appid       应用的唯一标识
        * @param redirectUri 用户同意授权后跳转的地址(如果用户同意授权, 会跳转到该地址, 并携带参数 code),【类似 controller 的地址】
        * @param scope       授权作用域, 有两种取值: snsapi_base(静默授权, 只得 openid)、snsapi_userinfo(弹出授权页面)
        * @return 进入授权页面的请求路径
        */
       public static String getAuthorizeUrl(String appid, String redirectUri, String scope) {
           return authorizeUrl.replace("gqAPPID", appid == null ? APP_ID : appid)
                   .replace("gqREDIRECT_URI", redirectUri)
                   .replace("gqSCOPE", scope)
                   .replace("gqSTATE", "zgq");
       }
    
       /**
        * 【方法】获取 access_token 以及 expires_in
        */
       private static void getAccessTokenExpiresIn() {
           HashMap<String, String> retMap = new HashMap<>();
           // 给请求 url 设值
           String url = accessTokenUrl.replace("gqAPPID", APP_ID).replace("gqAPPSECRET", APP_SECRET);
           // 向 url 发送网络请求, 获得返回值字符串
           String resultStr = restTemplate.getForObject(url, String.class);
           // 把 resultStr 转换为 JSON 格式
           JSONObject resultJSON = JSONUtil.parseObj(resultStr);
    
           String accessToken = resultJSON.get(ACCESS_TOKEN).toString(); // 凭证值
           String expiresIn = resultJSON.get(EXPIRES_IN).toString(); // 凭证有效时间
    
           accessTokenExpiresIn = new AccessTokenExpiresIn(accessToken, expiresIn);
       }
    
       /**
        * 【方法】获取 access_token
        *
        * @return access_token 值
        */
       public static String getAccessToken() {
           if (accessTokenExpiresIn == null || accessTokenExpiresIn.alreadyExpired())
               getAccessTokenExpiresIn();
           return accessTokenExpiresIn.getAccessToken();
       }
    
       /**
        * 组建返回值 Map
        *
        * @param params Map 的 key 和 value 的名称一样
        */
       private static Map<String, String> createResultMap(JSONObject resultJSON, String... params) {
           HashMap<String, String> resultMap = new HashMap<>();
           for (String p : params) {
               resultMap.put(p, resultJSON.get(p).toString());
           }
           return resultMap;
       }
    
       /**
        * 凭证和凭证有效时间类
        */
       @lombok.Data
       private static class AccessTokenExpiresIn {
           private String accessToken;
           // 过期时间
           private long expireTime;
    
           public AccessTokenExpiresIn(String accessToken, String expiresIn) {
               this.accessToken = accessToken;
               this.expireTime = System.currentTimeMillis() + Integer.parseInt(expiresIn) * 1000;
           }
    
           public boolean alreadyExpired() {
               return System.currentTimeMillis() > expireTime;
           }
       }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139

    前端的 redirect_uri 就是填写的 authOpenIds/h5,从而获取到 openid

    @RestController
    @RequestMapping("/authOpenIds")
    public class AuthOpenIdController { 
        /**
         * 授权后, 持久化 openid (把它保存在数据库中) 
         * 同时也可把 openid 保存到 Session 中
         * @param request 使用 request 把 openid 缓存到服务器 session 中
         */
        @ApiOperation("公众号 h5 授权")
        @GetMapping("/h5")
        public String h5(String code, String state, HttpServletRequest request) {
            String h5OpenId = OpenIdUtil.getH5OpenId(code);
            request.getSession().setAttribute("openid", h5OpenId); 
            System.out.println("h5OpenId: " + h5OpenId);
            return "成功获得";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    蓝桥杯(砝码称重,C++)
    Visual Studio 和 VSCode 哪个好?
    初探Java安全之JavaAgent
    kubernetes使用(1.25)
    Linux学习笔记(2)—文件基本属性
    IDEA配置全局生效-不是针对单个项目
    训练 fast point transformer
    [100天算法】-寻找峰值(day 63)
    win11使用qemu安装arm64 openEuler虚拟机 并虚拟机中在安装docker
    01【数据库的介绍】
  • 原文地址:https://blog.csdn.net/m0_54189068/article/details/126221377