公眾號授權獲取用戶信息及jwt登錄


文:公眾號授權獲取用戶信息及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 私信小編,切記:不懂一定要問

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM