2

SoringCloud(四) - 微信获取用户信息 - 化羽羽

 1 year ago
source link: https://www.cnblogs.com/xiaoqigui/p/16841694.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1、项目介绍

2793469-20221030171040007-1957509065.png

2、微信公众平台 和 微信开放文档

2.1 微信公众平台

2.1.1 网址链接

https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

2.1.2 测试号信息

2793469-20221030171050339-1286751882.png

2.1.3 微信扫描关注测试公众号

2793469-20221030171102230-1390793465.png

2.1.4 授权回调页面域名

2.1.4.1 网页服务->网页账号->修改
2793469-20221030171116829-582417977.png
2.1.4.2 填写 授权回调页面域名
2793469-20221030171125043-152088879.png
2.1.4.3 内网穿透 NATAPP
2.1.4.3.1 使用教程
NATAPP1分钟快速新手图文教程: https://natapp.cn/article/natapp_newbie

下载: https://natapp.cn/#download

使用本地配置文件config.ini: https://natapp.cn/article/config_ini
2.1.4.3.2 authtoken
2793469-20221030171137149-323770508.png
2.1.4.3.3 授权回调页面域名
2793469-20221030171145503-1815804314.png

2.2 微信开放文档

2.2.1 网址链接

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#2

2.2.2 官方 基本步骤教程

1 第一步:用户同意授权,获取code

2 第二步:通过 code 换取网页授权access_token

3 第三步:刷新access_token(如果需要)

4 第四步:拉取用户信息(需 scope 为 snsapi_userinfo)

5 附:检验授权凭证(access_token)是否有效

2793469-20221030171158229-1417514990.png

3、http请求工具类 HttpClient4Util

HttpClient4Util 用来发http请求;

https://www.cnblogs.com/xiaoqigui/p/16839536.html

4、配置文件 和 配置类

4.1 配置文件

application.yml

#端口
server:
  port: 8096

# 自定义微信授权信息
wechat:
  auth:
    app-id: wxd4e20add67******   #  appID
    app-secret: a21e97d21d0d6ce408b7a6c******  # appsecret
    code-uri: https://open.weixin.qq.com/connect/oauth2/authorize  # 请求微信官方获取用户授权code 的请求地址
    redirect-uri: http://******.natappfree.cc/wechat/auth/codeBack # 微信官方返回  用户授权code 的回调地址
    access-token-uri: https://api.weixin.qq.com/sns/oauth2/access_token # 根据微信回调的code值,请求微信官方获取用户access_token  的请求地址
    user-info-uri: https://api.weixin.qq.com/sns/userinfo #根据用户的 accessToken 和  openId 拉取用户信息  的请求地址

4.2 配置类

//自定义微信授权参数信息配置类
@Data
@Component
@ConfigurationProperties(prefix = "wechat.auth")
public class WeChatAuthConfig {
    /*
        应用id
     */
    private String appId;
    /*
        应用密钥
     */
    private String appSecret;
    /*
        请求获取code的地址
     */
    private String codeUri;
    /*
        微信官方回调code的地址
     */
    private String redirectUri;
    /**
     * 微信官方获取access_token地址
     */
    private String accessTokenUri;
    /*
        微信官方获取userInfo地址
     */
    private String userInfoUri;

}

5、server 层

5.1 微信授权的业务接口

/**
 * Created On : 28/10/2022.
 * <p>
 * Author : huayu
 * <p>
 * Description: 微信授权的业务接口
 */
public interface WeChatAuthService {

    //生成请求微信官方获取用户授权code的请求地址
    
    //根据微信回调的code值,请求微信官方获取用户access_token
    
    //根据用户的 accessToken 和  openId 拉取用户信息

}

5.1.1 生成请求微信官方获取用户授权code的请求地址

/**
* @author : huayu
* @date   : 28/10/2022
* @param  : []
* @return : java.lang.String
* @description : 生成请求微信官方获取用户授权code的请求地址
*/

String generateWeChatAuthCodeUrl();

5.1.2 根据微信回调的code值,请求微信官方获取用户access_token

/**
* @author : huayu
* @date   : 28/10/2022
* @param  : [wechatAuthCode]
* @return : java.lang.String
* @description : 根据微信回调的code值,请求微信官方获取用户access_token
*/
String getAccessTokenFromWechatUseCode(String wechatAuthCode);

5.1.3 根据用户的 accessToken 和 openId 拉取用户信息

/**
* @author : huayu
* @date   : 28/10/2022
* @param  : [accessToken, openId]
* @return : java.lang.String
* @description : 根据用户的 accessToken 和  openId 拉取用户信息
*/
String getUserInfoFromWechatUseAccessToken(String accessToken,String openId);

5.2 微信授权的业务接口 实现类

/**
 * Created On : 28/10/2022.
 * <p>
 * Author : huayu
 * <p>
 * Description: 微信授权的业务接口 实现类
 */
@Service
@Slf4j
public class WeChatAuthServiceImpl implements WeChatAuthService{

    //注入 http请求工具类
    @Autowired
    private WeChatAuthConfig weChatAuthConfig;
	
    //生成请求微信官方获取用户授权code的请求地址
    
    //根据微信回调的code值,请求微信官方获取用户access_token
    
    //根据用户的 accessToken 和  openId 拉取用户信息

}

5.2.1 生成请求微信官方获取用户授权code的请求地址

/**
* @author : huayu
* @date   : 29/10/2022
* @param  : []
* @return : java.lang.String
* @description : 生成请求微信官方获取用户授权code的请求地址
*/
@Override
public String generateWeChatAuthCodeUrl() {

    //微信官方引导用户打开授权页面,获取code的完整路径
    //https://open.weixin.qq.com/connect/oauth2/authorize
    // ?appid=APPID
    // &redirect_uri=REDIRECT_URI
    // &response_type=code
    // &scope=SCOPE
    // &state=STATE
    // #wechat_redirect
    //尤其注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问

    //生成请求卫星官方获取用户code的完整地址
    StringBuilder weCharAuthCodeUrl = new StringBuilder(weChatAuthConfig.getCodeUri());
    weCharAuthCodeUrl.append("?appid=").append(weChatAuthConfig.getAppId())
        .append("&redirect_uri=").append(weChatAuthConfig.getRedirectUri())
        .append("&response_type=code")
        //&scope=snsapi_userinfo&state=STATE
        .append("&scope=").append("snsapi_userinfo")
        .append("&state=").append("kh96_wechat_auth")
        .append("#wechat_redirect");

    log.info("------ 请求微信官方授权网站地址:{}  ------",weCharAuthCodeUrl.toString());

    //返货完整的请求地址
    return weCharAuthCodeUrl.toString();

}

5.2.2 根据微信回调的code值,请求微信官方获取用户access_token

/**
* @author : huayu
* @date   : 29/10/2022
* @param  : [wechatAuthCode]
* @return : java.lang.String
* @description : 根据微信回调的code值,请求微信官方获取用户access_token
*/
@Override
public String getAccessTokenFromWechatUseCode(String wechatAuthCode) {
    // 尤其注意:由于公众号的 secret 和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。
    // 请求方法:获取 code 后,请求以下链接获取access_token:
    // https://api.weixin.qq.com/sns/oauth2/access_token
    // ?appid=APPID
    // &secret=SECRET
    // &code=CODE
    // &grant_type=authorization_code

    // 封装根据code,请求微信官方获取access_token的完整地址
    StringBuilder accessTokenUrl = new StringBuilder(weChatAuthConfig.getAccessTokenUri());
    accessTokenUrl.append("?appid=").append(weChatAuthConfig.getAppId())
        .append("&secret=").append(weChatAuthConfig.getAppSecret())
        .append("&code=").append(wechatAuthCode)
        .append("&grant_type=authorization_code");

    log.info("------ 根据code,请求微信官方获取access_token的完整地址:{} ------", accessTokenUrl.toString());

    // 根据code,请求微信官方获取access_token,返回结果是同步返回的,不再是异步回调
    // 请求是服务器内部发起的,也就是说:在程序中,要根据上面完整的请求地址,主动发送请求到微信官方,接口同步会返回一个json格式的字符串结果,程序内要解析获取的结果

    // 程序内主动发起http请求,获取access_token
    return HttpClient4Util.getResponse4GetAsString(accessTokenUrl.toString(), "utf-8");
}

5.2.3 根据用户的 accessToken 和 openId 拉取用户信息

/**
* @author : huayu
* @date   : 29/10/2022
* @param  : [accessToken, openId]
* @return : java.lang.String
* @description : 根据用户的 accessToken 和  openId 拉取用户信息
*/
@Override
public String getUserInfoFromWechatUseAccessToken(String accessToken, String openId) {

    // 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和 openid 拉取用户信息了。
    // http:GET(请使用 https 协议):
    // https://api.weixin.qq.com/sns/userinfo
    // ?access_token=ACCESS_TOKEN
    // &openid=OPENID
    // &lang=zh_CN

    // 封装根据accessToken和openId,请求微信官方获取用户信息详情地址
    StringBuilder userInfoUrl = new StringBuilder(weChatAuthConfig.getUserInfoUri());
    userInfoUrl.append("?access_token=").append(accessToken)
        .append("&openid=").append(openId)
        .append("&lang=zh_CN");
    log.info("------ 根据access_token,请求微信官方获取userinfo的完整地址:{} ------", userInfoUrl.toString());

    // 程序内主动发起http请求,获取用户详情
    return HttpClient4Util.getResponse4GetAsString(userInfoUrl.toString(), "utf-8");
}

6、controller 层

/**
 * Created On : 28/10/2022.
 * <p>
 * Author : huayu
 * <p>
 * Description: 测试微信授权登录操作入口
 */
//@SuppressWarnings("all")
@Slf4j
@RestController
@RequestMapping("/wechat/auth")
public class WeChatAuthController {

    //注入service层实现类
    @Autowired
    private WeChatAuthService weChatAuthService;

}

6.1 获取请求微信官方货物code的完整地址,用户访问该地址

/**
* @author : huayu
* @date   : 28/10/2022
* @param  : []
* @return : com.kgc.scd.uitl.RequestResult<java.lang.String>
* @description :  获取请求微信官方货物code的完整地址,用户访问该地址,可以进行授权操作(把地址交给前端生成二维码给用户扫码,或者后端生成)
*/
@GetMapping("/codeUrl")
public RequestResult<String> codeUrl(){

    //调用业务接口,获取完整用户授权访问的地址
    return ResultBuildUtil.success(weChatAuthService.generateWeChatAuthCodeUrl());

}

6.2 获取用户详情信息

用户授权后,接收微信官方异步回调请求,获取用户授权的code:(code,state)
	1.通过 code 换取网页授权access_token
	2.拉取用户信息(需 scope 为 snsapi_userinfo)
	3.接口返回用户详情信息
/**
* @author : huayu
* @date   : 28/10/2022
* @param  : []
* @return : com.kgc.scd.uitl.RequestResult<java.util.Map<java.lang.String,java.lang.Object>>
* @description : 接收微信官方异步回调请求,获取用户授权的code
* 流程:用户先根据上一步返回请求地址,进行授权操作,如果用户统一授权,微信官方自动根据上一步请求带过去的回调地址redirectUri,进行结果回调
*/
@RequestMapping("/codeBack")
public RequestResult<Map<String, Object>> codeBack(HttpServletRequest request){

    // 用户同意授权后,如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
    // code说明:code作为换取access_token的票据,每次用户授权带上的 code 将不一样,code只能使用一次,5分钟未被使用自动过期。

    // 从官方回调的请求中,获取用户授权后的code参数值
    String wechatAuthCode = request.getParameter("code");
    // 从官方回调的请求中,获取用户授权时的自定义参数state
    String wechatAuthState = request.getParameter("state");

    log.info("------ 微信授权后,官方异步回调结果:code={},state={} ------", wechatAuthCode, wechatAuthState);

    // 定义接口返回集合对象
    Map<String, Object> resultMap = new HashMap<>();

    // 参数非空校验
    if(StringUtils.isBlank(wechatAuthCode)){
        resultMap.put("msg", "授权code为空!");
        return ResultBuildUtil.fail(resultMap);
    }

    // 1. 调用业务接口,通过 code 换取网页授权access_token
    String accessTokenJson = weChatAuthService.getAccessTokenFromWechatUseCode(wechatAuthCode);
    log.info("------ 通过 code 换取网页授权access_token返回结果:{} ------", accessTokenJson);

    // 正确时返回的 JSON 数据包如下:
    // {"access_token":"ACCESS_TOKEN","expires_in":7200,"refresh_token":"REFRESH_TOKEN","openid":"OPENID","scope":"SCOPE"}
    // 错误时返回的 JSON 数据包如下:
    // {"errcode":40029,"errmsg":"invalid code"}

    // 解析返回的json数据
    JSONObject accessTokenJsonObj = JSON.parseObject(accessTokenJson);

    // 判断获取access_token结果是否正确,如果错误,直接结束,如果正确,获取对应的access_token
    if(StringUtils.isNotBlank(accessTokenJsonObj.getString("errcode"))){
        resultMap.put("wxCode", accessTokenJsonObj.getString("errcode"));
        resultMap.put("wxMsg", accessTokenJsonObj.getString("errmsg"));
        return ResultBuildUtil.fail(resultMap);
    }

    // 2. 拉取用户信息(需 scope 为 snsapi_userinfo)
    // 根据上一步返回json,获取拉取用户信息凭证-access_token和用户唯一标识-openid
    String accessToken = accessTokenJsonObj.getString("access_token");
    String openId = accessTokenJsonObj.getString("openid");

    //  调用业务接口,通过access_token和openId,拉取用户详情
    String userInfoJson = weChatAuthService.getUserInfoFromWechatUseAccessToken(accessToken, openId);
    log.info("------ 通过access_token和openId,拉取用户详情:{} ------", userInfoJson);

    // 3.接口返回用户详情信息
    resultMap.put("userInfo", userInfoJson);

    // TODO 获取成功用户信息后,系统要完成静默注册-把用户信息注册到系统数据中,存储用户的头像,昵称,openId信息,并给系统用户表增加其它的基本信息

    //返回用户详情
    return ResultBuildUtil.success(resultMap);
}

7.1 生成请求微信官方获取用户授权code的请求地址

2793469-20221030171222050-691773510.png

7.2 获取用户信息

2793469-20221030171230711-1031872244.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK