文:公眾號授權獲取用戶信息及jwt登錄
最近有個小伙伴問了我關於"公眾號授權及JWT登錄"問題,小編也是在空閑之余,堅持不懈,寫下此文,和大家分享和學習 ↓↓↓
前言
什么是微信公眾號授權登錄?微信授權又是什么?jwt 怎么和微信授權結合使用?小編也不多BB 結合實際開發和大家聊聊↓↓↓
什么是微信小程序授權 ?
官網: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
小編就不多BB先來張圖 壓壓驚
授權及JWT實操
1、controller層
@Slf4j @RestController @RequestMapping("/OAuth") public class OAuthController { @Resource private OAuthService oAuthService; //授權service層接口 @Resource private HttpServletRequest request; @Resource private HttpServletResponse response; @Resource private 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,因為當用戶點擊授權后,會跳轉到授權后重定向地址,也就是這個方法,從而攜帶過來code oAuthService.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 { @Resource private WeChatAuthorizeUtil weChatAuthorizeUtil; //授權工具類 @Resource private UserMapper userMapper; //userMapper層 @Resource private CommonTemplateService templateService; //公共service層 @Resource private JwtUtils jwtUtils; //jwt 工具類 @Resource private HttpServletResponse response; @Resource private WechatConfig wechatConfig; //微信配置文件 @Override public 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"; @Resource private 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_token private String openid; //用戶唯一標識,請注意,在未關注公眾號時,用戶訪問公眾號的網頁,也會產生一個用戶和公眾號唯一的OpenID private 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; //國家,如中國為CN private String headimgurl; //用戶頭像,最后一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),用戶沒有頭像時該項為空。若用戶更換頭像,原有頭像URL將失效。 private String privilege; //用戶特權信息,json 數組,如微信沃卡用戶為(chinaunicom) private String unionid; //只有在用戶將公眾號綁定到微信開放平台帳號后,才會出現該字段 }
7、JwtUtils
@Slf4j @Component public class JwtUtils { private JwtUtils() { } @Resource private 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); //用戶userId claims.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 私信小編,切記:不懂一定要問