微信公众号授权获取用户信息及jwt登录

article/2025/10/1 21:21:26

Java 微信公众号授权获取用户信息及jwt登录 !!!

前言

前几篇文章小编分享过:

  • 微信小程序授权+获取用户手机号 + jwt登录 (含源码)
  • 微信小程序支付 + 公众号支付 (含源码)

工作之余,分享下 “ 微信公众号授权 + 获取用户信息 + jwt登录

一、公众号授权获取用户信息及jwt

1、什么是微信公众号授权登录 ?

官网:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
在这里插入图片描述

当我们进入某个公众号时,可能出现上图界面,那具体是怎么实现的呢?

别急,小编在这里和大家浅聊微信授权

二、授权及jwt 实操

★★★:项目全貌

★★★ 若需要“源码”,请看最后 ★★★

  • 项目架构:springboot + mybatis
  • 数据库: mysql
  • 开发环境:jdk8、idea
  • 授权: 微信公众号授权
1、controller层
@Slf4j
@RestController
@RequestMapping("/OAuth")
public class OAuthController {@Resourceprivate OAuthService oAuthService; //授权service层接口@Resourceprivate HttpServletRequest request;@Resourceprivate HttpServletResponse response;@Resourceprivate WeChatAuthorizeUtil weChatAuthorizeUtil; //微信授权工具类, 后面有/***  第一步:前段调用此方法,当用户点击同意授权后,* 		  小编直接让他跳转调下面那个方法(/getOAuth)来获取网页授权access_token*	★★★:redirect_uri 授权后重定向的回调链接地址*			这个值填写的是下面 那个方法的url*/@ApiOperation(value = "授权登录", response = String.class)@GetMapping(value = "/getCode")public void loginInit() {try {response.sendRedirect(weChatAuthorizeUtil.getOAuthCodeUrl_USER()); } catch (UnsupportedEncodingException e) {log.error("重定向url编码失败:>> " + e.getMessage());e.printStackTrace();} catch (Exception e) {log.error(" response重定向失败:>> " + e.getMessage());}}@GetMapping(value = "/getOAuth")public void getOAuth() {try {		//此处直接获取请求的code,因为当用户点击授权后,会跳转到授权后重定向地址,也就是这个方法,从而携带过来codeoAuthService.getWXUserInfoOAuth(request.getParameter(ColumnName.CODE));} catch (Exception e) {log.error("getOAuth error: ", e);}}
}
2、service层
public interface OAuthService {void getWXUserInfoOAuth(String code); //授权获取用户信息接口}
3、serviceImpl层
@Service
@Slf4j
public class OAuthServiceImpl implements OAuthService {@Resourceprivate WeChatAuthorizeUtil weChatAuthorizeUtil; //授权工具类@Resourceprivate UserMapper userMapper; //userMapper层@Resourceprivate CommonTemplateService templateService; //公共service层@Resourceprivate JwtUtils jwtUtils;  //jwt 工具类@Resourceprivate HttpServletResponse response;@Resourceprivate WechatConfig wechatConfig; //微信配置文件@Overridepublic void getWXUserInfoOAuth(String code) {try {if (StringUtils.isBlank(code)) { 			//判断请求 code 是否为空log.error(" CODE_NOT_EMPTY_ERROR : << {} >>", RespResultEnum.CODE_NOT_EMPTY_ERROR.getMessage());}UserRegisterRespDTO registerRespDTO = null; //自己封装的,返回给前段的数据(包含jwt中加密的token,和用户的信息)ResponseEntity<String> responseEntity = 	//使用resttemplate向微信提供的url(通过code换取网页授权access_token url)发送请求templateService.getForEntity(weChatAuthorizeUtil.getAccessTokenUrl(code));if (responseEntity.getStatusCode().value() != HttpStatus.OK.value()) { //判断请求是否成功log.error(" VISIT_WEIXIN_API_ERROR : << {} >>", RespResultEnum.VISIT_WEIXIN_API_ERROR.getMessage()+ responseEntity.getStatusCodeValue());}WeiXinOAuthRespDTO weiXinOAuthRespDTO =		//获取微信“通过code换取网页授权access_token”返回的信息,并封装到自己的DTO中JSON.parseObject(responseEntity.getBody(), WeiXinOAuthRespDTO.class);log.info("weiXinOAuthRespDTO : " + weiXinOAuthRespDTO.toString()); //日志打印if (StringUtils.isBlank(weiXinOAuthRespDTO.getOpenid())) { //判断返回的openID是否为空log.error(" WEIXIN_CODE_ERROR : << {} >>", RespResultEnum.WEIXIN_CODE_ERROR.getMessage());}ResponseEntity<String> responseUserInfo = //使用resttemplate向微信提供的url(拉取用户信息 url)发送请求templateService.getForEntity(weChatAuthorizeUtil.getUserInfoUrl(weiXinOAuthRespDTO.getAccess_token(), weiXinOAuthRespDTO.getOpenid()));if (responseEntity.getStatusCode().value() != HttpStatus.OK.value()) { //判断请求是否成功log.error(" VISIT_WEIXIN_API_ERROR : << {} >>", RespResultEnum.VISIT_WEIXIN_API_ERROR.getMessage()+ responseEntity.getStatusCodeValue());}WeiXinOAuthUserInfoRespDTO userInfoRespDTO = 	//获取微信“拉取用户信息”返回的信息,并封装到自己的DTO中(此dto包含用户头像,昵称等)JSON.parseObject(responseUserInfo.getBody(), WeiXinOAuthUserInfoRespDTO.class);if (StringUtils.isBlank(userInfoRespDTO.getOpenid())) {log.error(" WEIXIN_USER_INFO_ERROR : << {} >>", RespResultEnum.WEIXIN_USER_INFO_ERROR.getMessage());}log.info("weiXinOAuth user info: " + userInfoRespDTO.toString());UserDO userDO = getUserByOpenId(userInfoRespDTO.getOpenid()); //此方法在下面if (userDO != null ) { // == null 说明 该用户第一次授权(此时:我们需要做两点==> 1、把用户信息保存到数据库;2、给前段签发token)//用户数据保存 数据库(省略。。。)//下面通过jwt向前段签发token(两个参数:1、userId,2、用户角色)String token = jwtUtils.generateJwt(userDO.getUserId(),String.valueOf(UserTypeEnum.WEI_XIN_USER.getUserType()));registerRespDTO = respDTO(userDO, token);// 由于项目含有不在公众号中的登录方式:因此,做了一下的从定向,(如果你项目自有公众号,到上面那一步就结束了,也就是说直接返回 registerRespDTO 就行,其中包含用户信息,以及token)response.sendRedirect(JumpUrlUtil.getValidUrl(WeiXinOAuthColumn.JUMP_MAIN_METHOD,wechatConfig.getJumpUri(), JumpUrlUtil.transBeanToMap(registerRespDTO)));return;}//此处说明用户 不是第一次授权,数据库已经有用户信息,直接签发token跳转页面(若自有工作号,直接返回,不用从定向)response.sendRedirect(JumpUrlUtil.getValidUrl(WeiXinOAuthColumn.JUMP_LOGIN_METHOD,wechatConfig.getJumpUri(), JumpUrlUtil.transBeanToMap(userInfoRespDTO)));return;} catch (Exception e) {log.error(" getWXUserInfoOAuth error: " + e.getMessage());}/***	根据openid查询用户数据库DO(userDO)*/private UserDO getUserByOpenId(String openId) {QueryWrapper<UserDO> queryWrapper = new QueryWrapper<>();queryWrapper.eq(ColumnName.OPEN_ID, openId);return userMapper.selectOne(queryWrapper);}}
4、WeChatAuthorizeUtil
@Slf4j
@Component
public class WeChatAuthorizeUtil {private static String ENCODE = "UTF-8";@Resourceprivate WechatConfig wechatConfig;// 微信授权 用户无感知 url(也就是用户不用点授权也能获取openID(不包含昵称、地区等),前提:在公众号内)public String getOAuthCodeUrl_BASE() throws UnsupportedEncodingException {return WeiXinOAuthColumn.OAUTH_CODE_URI.replace("APPID", wechatConfig.getAppId()).replace("REDIRECT_URI", URLEncoder.encode(wechatConfig.getFirstCodeRedirectUrl(), ENCODE)).replace("SCOPE", WeiXinOAuthColumn.SNSAPI_BASE).replace("STATE", WeiXinOAuthColumn.STATE);}// 微信授权 用户有感知 url(也就是需要用户点击授权才行)public String getOAuthCodeUrl_USER() throws UnsupportedEncodingException {return WeiXinOAuthColumn.OAUTH_CODE_URI.replace("APPID", wechatConfig.getAppId()).replace("REDIRECT_URI", URLEncoder.encode(wechatConfig.getLoginCodeRedirectUrl(), ENCODE)).replace("SCOPE", WeiXinOAuthColumn.SNSAPI_USERINFO).replace("STATE", WeiXinOAuthColumn.STATE);}// 微信授权 获取用户openID url( 也就是:通过code换取网页授权access_token)public String getAccessTokenUrl(String code) {return WeiXinOAuthColumn.OAUTH_ACCESS_TOKEN_URI.replace("APPID", wechatConfig.getAppId()).replace("SECRET", wechatConfig.getSecretKey()).replace("CODE", code);}// 微信授权 获取用户信息( 也就是:拉取用户信息(需scope为 snsapi_userinfo))public String getUserInfoUrl(String accessToken, String openid) {return WeiXinOAuthColumn.OAUTH_USER_INFO_URI.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openid);}
5、WeiXinOAuthRespDTO
/**
*	微信授权: 调用通过code换取网页授权access_token 的url, 对返回参数封装成自己的DTO
*/
@Data
public class WeiXinOAuthRespDTO {private String access_token;  //网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同private String expires_in;    //access_token接口调用凭证超时时间,单位(秒)private String refresh_token; //用户刷新access_tokenprivate String openid;        //用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenIDprivate String scope;         //用户授权的作用域,使用逗号(,)分隔}
6、WeiXinOAuthUserInfoRespDTO
/**
*	微信授权: 调用 拉取用户信息(需scope为 snsapi_userinfo)的url, 对返回参数封装成自己的DTO
*/
@Data
public class WeiXinOAuthUserInfoRespDTO {private String openid;private String nickname; //用户昵称private String sex; //用户的性别,值为1时是男性,值为2时是女性,值为0时是未知private String province; //用户个人资料填写的省份private String city;    //普通用户个人资料填写的城市private String country; //国家,如中国为CNprivate String headimgurl; //用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。private String privilege;  //用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)private String unionid; //只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段
//    /**
//     * 是否注册(1、已注册,2未注册)
//     */
//    private Integer reg;
}
7、JwtUtils
@Slf4j
@Component
public class JwtUtils {private JwtUtils() {}@Resourceprivate JwtConfig jwtConfig;/*** 加密* @param userId* @return*/public String generateJwt(Long userId, String userType) {byte[] encode = Base64.getEncoder().encode(jwtConfig.getSecurityKey().getBytes());Map<String, Object> claims = Maps.newHashMap();claims.put(ColumnName.USER_ID, userId); 	//用户userIdclaims.put(ColumnName.USER_TYPE, userType);	//用户角色return Jwts.builder().addClaims(claims) //内容.setIssuedAt(TimeUtil.now()) //发行时间.setExpiration(TimeUtil.getExpiration(jwtConfig.getOutTime())) //超时时间.signWith(SignatureAlgorithm.HS512, encode).compact();}/*** 解密* @param token* @return*/public Claims extractJwt(String token) {try {byte[] encode = Base64.getEncoder().encode(jwtConfig.getSecurityKey().getBytes());return Jwts.parser().setSigningKey(encode).parseClaimsJws(token).getBody();} catch (Exception ex) {log.error("parseJWT error for {}", token);return null;}}

★★ 注意 ★★

  • 由于授权相关代码比较多,小编就不挨个粘贴了,还望小伙伴多多谅解;
  • 若需完整 “ 源码 ” 请按照下面方式获取

★★ 推荐 ★★

  • 微信小程序授权+获取用户手机号 + jwt登录 (含源码)
  • 微信小程序支付 + 公众号支付 (含源码)

若有需要源码的小伙伴,可以扫描下面公众号,回复:公众号授权及JWT登录 小编直接发百度网盘↓↓↓
也可以加小编微信:CodeCow-6666 私信小编,切记:不懂一定要问,被骂也值

在这里插入图片描述

《 岁月匆忙,偷得浮生半日闲—— 午休之余写下此文!! 》


http://chatgpt.dhexx.cn/article/hKxXHWGJ.shtml

相关文章

手把手教程用Java实现微信公众号扫码登录功能

文章目录 前言一、环境准备二、使用步骤1. 使用微信工具包2. 创建数据表3. 登录页面代码逻辑4. 验证微信公众号登录 总结 前言 微信现今是我们必不可少的社交工具了&#xff0c;围绕微信这个生态实际上有很多东西可以做&#xff0c;我们经常会看到一些网站通过微信扫码进如公众…

[一维前缀和]leetcode303:区域和检索 - 数组不可变(easy)

题目&#xff1a; 题解&#xff1a; 一维前缀和&#xff0c;元素数组[0,j]的前缀和对应prefix[j1] 代码如下&#xff1a; class NumArray { private:vector<int> prefix; public://题解&#xff1a;一维前缀和NumArray(vector<int>& nums) {int nnums.size()…

前缀和矩阵前缀和

前缀和 前缀和是一种重要的预处理&#xff0c;能大大降低查询的时间复杂度。我们可以简单理解为“数列的前 n n n 项的和”。 例题 有 N N N 个的正整数放到数组 A A A 里&#xff0c;现在要求一个新的数组 B B B&#xff0c;新数组的第 i i i 个数 B [ i ] B[i] B[i]…

【算法基础】一维前缀和 + 二维前缀和

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;【C/C】算法 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有…

前缀和与差分总结

目录 1.前缀和 2.前缀和算法的好处 3.二维前缀和 4.差分 5.一维差分 6.二维差分 1.前缀和 前缀和是指某序列的前n项和&#xff0c;可以把它理解为数学上的数列的前n项和&#xff0c;而差分可以看成前缀和的逆运算。合理的使用前缀和与差分&#xff0c;可以将某些复杂的…

一维前缀和

今天我们来讲讲一维前缀和 首先我们来介绍一下一维前缀和&#xff0c;emmm其实和数列的前n项和差不多&#xff0c;它能在 O ( 1 ) O(1) O(1) 的时间复杂度操作数组的任意子区间&#xff0c;比如我们要找出一段区间的和。 我们先预处理出一个前缀和数组&#xff0c;为了方便使…

【算法】前缀和(一维前缀和与二维前缀和)

前缀和是一种重要的预处理&#xff0c;能大大降低查询的时间复杂度。 【一维前缀和】 给定一个数组A[1,2,……n]&#xff0c;则它的前缀和数组为PrefixSum[1..n]。定义为&#xff1a;PrefixSum[i] A[0]A[1]...A[i-1]&#xff1b; 【例子】 A[5,6,7,8] --> PrefixSum[5,…

【Python 百练成钢】前缀和

文章目录 前言&#x1f607;一维前缀和&#x1f608;问题描述问题分析代码实现 二维前缀和&#x1f47f;问题描述问题分析代码实现 ฅʕ•̫͡•ʔฅ&#x1f4af; 前言&#x1f607; 今天分享一下学到的基础算法前缀和。 首先了解一下前缀和的基础概念&#x1f604; 有一个序列…

【每日一算法】二维前缀和算法 _ 模板应用

&#x1f49b; 前情提要&#x1f49b; 本章节是每日一算法的二维前缀和算法的相关知识~ 接下来我们即将进入一个全新的空间&#xff0c;对代码有一个全新的视角~ 以下的内容一定会让你对数据结构与算法有一个颠覆性的认识哦&#xff01;&#xff01;&#xff01; ❗以下内容…

基础算法:二维前缀和

二维前缀和C模板&#xff1a; S[i, j] 第i行j列格子左上部分所有元素的和 S[i, j] S[i-1,j] s[i,j-1] - S[i-1,j-1] a[i,j](表示当前的数) 以(x1, y1)为左上角&#xff0c;(x2, y2)为右下角的子矩阵的和为&#xff1a; S[x2, y2] - S[x1-1,y2] - S[x2,y1-1] S[x1-1,y1-1]…

二维前缀和

二维前缀和 直接看一个例子 假设给定一个矩阵 1 2 4 3 5 1 2 4 6 3 5 9 那么&#xff0c;可以推出他的二维前缀和矩阵为 1 3 7 10 6 9 15 22 12 18 29 45 在二维前缀和数组中&#xff0c;9 1 2 5 1 15 1 2 5 1 4 2 18 1 5 6 2 1 3… … 即二位前缀和数组中第 …

二维数组前缀和

二维数组前缀和 对于二维数组求前缀和,我们先预处理第一行跟第一列的前缀和 第一行跟第一列的前缀和可以看作一维数组的前缀和 前缀和数组的0,0等于原数组的0,0,第一行为原数组第一行的前缀和,第一列为第一列的前缀和 预处理: //原数组 int arr[110][110]{{},{0,1,2,3,4,5,…

前缀和与经典例题详解

前缀和与及经典例题详解 南昌理工ACM集训队 这是目录 前缀和与及经典例题详解前言前缀和P5638 光骓者的荣耀 二维前缀和P2004 领地选择 最大子段和P1115 最大子段和P1719 最大加权矩形 写在最后 前言 下面的例题都出自于洛谷官方算法2-1题单&#xff0c;有兴趣的同学可以去水…

前缀和(C/C++)

目录 1. 前缀和的定义 2. 一维前缀和 2.1 计算公式 2.2 用途 2.3 小试牛刀 3. 二维前缀和 3.1 用途 1. 前缀和的定义 对于一个给定的数列A&#xff0c;他的前缀和数中 S 中 S[ i ] 表示从第一个元素到第 i 个元素的总和。 如下图&#xff1a;绿色区域的和就是前缀和数组…

前缀和(C++)实现

每日一句&#xff1a;真正让人变好的选择过程都不会很舒服&#xff0c;所以人们明知道什么都不做&#xff0c;会比较轻松&#xff0c;但依旧选择追逐梦想。 前缀和 前言一、一维前缀和1.前缀和是什么&#xff1f;2.暴力做法3.前缀和求区间大小3.1如何构成前缀和的形式&#xff…

差分与前缀和

目录 前言 一、算法原理 二、算法图解 三、算法模板 四、算法应用 前言 天梯赛和省赛快开始了&#xff0c;不想拖后腿&#xff0c;边更边学习吧。 酝酿好久的第一篇博客&#xff0c;缺点不少&#xff0c;多多指教吖。 点赞鼓励一下吧&#xff0c;亲。&#x1f619;&#x1…

算法设计 - 前缀和 差分数列

一维数组前缀和的概念 前缀和的概念很简单&#xff0c;我们用一维数组的前缀和来举例&#xff0c;有如下一维数组&#xff1a; arr [1, 2, 3, 4, 5] 该数组的前缀和数组如下 preSum [1, 3, 6, 10, 15] 关系如下&#xff1a; preSum[0] arr[0]preSum[1] arr[0] arr[1]pre…

python 前缀和总结

前缀和是数据结构与算法中比较重要的知识&#xff0c;前缀和经常可以结合哈希表解决很多有意思的问题。为了方便学习&#xff0c;在这里总结leetcode中出现的前缀和问题。 525. 连续数组 给定一个二进制数组 nums &#xff08;只含有0&#xff0c;1&#xff09;, 找到含有相同…

【c++入门(2)】前缀和

大纲 1.计算前缀和 2.计算字段和 3.后缀和 4.前缀积 5.后缀积 6.例题 1.计算前缀和 基础问题&#xff1a; 思路1&#xff1a; 枚举 cin (); for (int i 1; i < q; i) {cin >> x;int sum 0;for (int j 1; j < x; j){sum a[j];}cout << sum << endl…

前缀和

【前缀和】 什么是前缀和&#xff1f;前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和。 设b[]为前缀和数组&#xff0c;a[]为原数组&#xff0c;根据这句话可以得到前缀和的定义式和递推式&#xff1a; 定义式递推式一维前缀和 二维前缀和 【一维前缀和】…