实现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>

在这里插入图片描述

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;
       }
   }

}


前端的 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 "成功获得";
    }

}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jagochan 张国庆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值