开放平台–扫描微信二维码登录

准备

如不了解第三方登录流程,建议先大概了解一下,在来看看代码。
说明: 由于开放平台无测试号测试,所以只能上开放平台进行配置信息。公众平台的测试号并不能给开放平台使用。

微信开放平台地址:https://open.weixin.qq.com/cgi-bin/index?t=home/index&lang=zh_CN

配置步骤如下:

1、创建web应用
在这里插入图片描述
当创建成功的时候会有appidappsecret,下面代码需要用到。
创建好之后需要设置回调域 ,就是当扫码通过之后会调用该域内的地址,地址在下面代码种配置。

2、注意!!!
1、设置回调域的时候,前面不能加上http://等协议。只需要配置域名即可,如baidu.com,spring.io等。填写成http://spring.io/是错误的
2、域名不能加端口号

代码

<一> 获取二维码

  /**
   * 跳转至微信登录界面
   */
  // Result 定义的类,返回给前端的信息
  @ApiOperation(value = "网站-微信扫码登录路径", notes = "网站-微信扫码登录路径")
  @GetMapping(value = "/web/wxLoginPage")
  public Result webWxKfLoginPage() throws Exception {
    String url = WeChatLoginUtil.webWxKfLoginPage();
    return Result.Builder.newBuilder(AppTipStatusEmum.SUCCESS_STATUS.getCode(), AppTipMsgEnum.SELECT_SUCCESS.getText()).setMessage("获取二维码成功!").setData(url).build();
  }

涉及的WeChatLoginUtil类如下:

import com.uwa.mall.user.module.enums.ThirdPartyLoginEnum;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class WeChatLoginUtil {

  // ===============================================web方式==================================================

  // 网页方式登录(scope=snsapi_login)
  public static String webWxKfLoginPage() throws Exception {
    // 防止csrf攻击(跨站请求伪造攻击)
    String state = UUID.randomUUID().toString().replaceAll("-", "");
    // 存入redis。 CacheUtil为封装redis的工具类
    CacheUtil.set(ThirdPartyLoginEnum.WeChatEnum.WeChatKFState.getCode() + state, "ok", Integer.valueOf(ThirdPartyLoginEnum.WeChatEnum.WeChatKFStateTime.getCode()));
    // 普通微信三方地址
    String url = ThirdPartyLoginEnum.WeChatEnum.AppUrl.getCode() + "appid=" + ThirdPartyLoginEnum.WeChatEnum.AppID.getCode() + "&redirect_uri=" + ThirdPartyLoginEnum.WeChatEnum.RedirectUri.getCode()
        + "&response_type=code&scope=snsapi_login&state=" + state + "#wechat_redirect";

    return url;
  }

  /**
   * 通过code获取token
   *
   * @return
   */
  public static Map getAccessToken(String code, String appid, String secret) throws Exception {
    // 构建请求数据
    Map t = new HashMap();
    t.put("appid", appid);
    t.put("secret", secret);
    t.put("code", code);
    t.put("grant_type", "authorization_code");

    // 调用httpclient处理请求得到返回json数据
    String returnJson = HttpClientUtil.httpGet(ThirdPartyLoginEnum.WeChatEnum.AccessTokenUri.getCode(), t);
    Map token = JsonUtil.fromJson(returnJson, Map.class);
    return token;
  }

  /**
   * 刷新token处理
   *
   * @return
   */
  public static Map refreshToken(String appid, String refresh_token) throws Exception {
    // 构建请求参数
    Map m = new HashMap();
    m.put("appid", appid);
    m.put("grant_type", "refresh_token");
    m.put("refresh_token", refresh_token);

    String s = HttpClientUtil.httpGet(ThirdPartyLoginEnum.WeChatEnum.UrlRefresh.getCode(), m);

    // 调用httpclient发出请求
    Map refreshToken = JsonUtil.fromJson(s, Map.class);
    return refreshToken;
  }

  /**
   * 通过token获取用户信息
   * 
   * @param token
   * @return
   */
  public static String getUserInfo(Map token) throws Exception {
    // 构建请求数据
    Map u = new HashMap();
    u.put("access_token", token.get("access_token"));
    u.put("openid", token.get("openid"));
    u.put("lang", "zh_CN");
    // 调用httpclient处理请求得到用户信息json数据
    String userinfo = HttpClientUtil.httpGet(ThirdPartyLoginEnum.WeChatEnum.UrlUserInfo.getCode(), u);

    return userinfo;
  }

  // ===============================================公众号方式==================================================


  // 公众号方式登录(scope=snsapi_base)
  public static String publicWxKfLoginPage() {
    String state = UUID.randomUUID().toString().replaceAll("-", "");
    CacheUtil.set(ThirdPartyLoginEnum.PublicWeChatEnum.WeChatKFState.getCode() + state, "ok", Integer.valueOf(ThirdPartyLoginEnum.PublicWeChatEnum.WeChatKFStateTime.getCode()));
    String url = ThirdPartyLoginEnum.PublicWeChatEnum.AppUrl.getCode() + "appid=" + ThirdPartyLoginEnum.PublicWeChatEnum.AppID.getCode() + "&redirect_uri="
        + ThirdPartyLoginEnum.PublicWeChatEnum.RedirectUri.getCode() + "&response_type=code&scope=snsapi_userinfo&state=" + state + "#wechat_redirect";
    return url;
  }


  // 公众号 通过code获取token
  public static Map getAccessTokenByPublic(String code, String appid, String secret) throws Exception {
    // 构建请求数据
    Map t = new HashMap();
    t.put("appid", appid);
    t.put("secret", secret);
    t.put("code", code);
    t.put("grant_type", "authorization_code");

    // 调用httpclient处理请求得到返回json数据
    String returnJson = HttpClientUtil.httpGet(ThirdPartyLoginEnum.PublicWeChatEnum.AccessTokenUri.getCode(), t);
    Map token = JsonUtil.fromJson(returnJson, Map.class);
    return token;
  }

  public static Map refreshTokenByPublic(String appid, String refresh_token) throws Exception {
    // 构建请求参数
    Map m = new HashMap();
    m.put("appid", appid);
    m.put("grant_type", "refresh_token");
    m.put("refresh_token", refresh_token);

    String s = HttpClientUtil.httpGet(ThirdPartyLoginEnum.PublicWeChatEnum.UrlRefresh.getCode(), m);

    // 调用httpclient发出请求
    Map refreshToken = JsonUtil.fromJson(s, Map.class);
    return refreshToken;
  }

  public static String getUserInfoByPublic(Map token) throws Exception {
    // 构建请求数据
    Map u = new HashMap();
    u.put("access_token", token.get("access_token"));
    u.put("openid", token.get("openid"));
    u.put("lang", "zh_CN");
    // 调用httpclient处理请求得到用户信息json数据
    String userinfo = HttpClientUtil.httpGet(ThirdPartyLoginEnum.PublicWeChatEnum.UrlUserInfo.getCode(), u);

    return userinfo;
  }

}

涉及的ThirdPartyLoginEnum枚举接口类如下:

// 第三方登录方式
public interface ThirdPartyLoginEnum {

  // 网页微信登录方式
  enum WeChatEnum {
    AppID("xxx.....xxx","微信开发平台的AppID"),
    AppSecret("xxx.....xxx","微信开发平台的AppSecret"),
    AppUrl("https://open.weixin.qq.com/connect/qrconnect?","微信第三方地址"),
    RedirectUri("http://www.ycj.com/login/wxLogin","登录成功的回调地址"),  //这里的域名和前面配置的域名必须一致,且不能加端口号
    AccessTokenUri("https://api.weixin.qq.com/sns/oauth2/access_token","获取access_token的地址"),
    UrlRefresh("https://api.weixin.qq.com/sns/oauth2/refresh_token","刷新获取微信token"),
    UrlUserInfo("https://api.weixin.qq.com/sns/userinfo","获取用户信息"),
    WeChatKFState("wechat-kf-state","redis的key"),
    WeChatKFStateTime("300","redis的key的过期时间(秒)");

    private String code;
    private String msg;

    WeChatEnum(String c, String m) {
      this.code = c;
      this.msg = m;
    }

    public String getCode() {
      return code;
    }
    public String getMsg() {
      return msg;
    }
  }

  // 公众号微信登录方式(移动端)
  enum PublicWeChatEnum {
    AppID("xxx.....xxx","微信公众平台的AppID"),
    AppSecret("xxx.....xxx","微信公众平台的AppSecret"),
    AppUrl("https://open.weixin.qq.com/connect/oauth2/authorize?","微信第三方地址"),
    RedirectUri("http://activate.navicat.com/mall/user/api/loginAndRegister/public/wxLoginCallback","登录成功的回调地址"),  //这里的域名和公众平台(不是本文的)配置的域名必须一致,且不能加端口号
    AccessTokenUri("https://api.weixin.qq.com/sns/oauth2/access_token","获取access_token的地址"),
    UrlRefresh("https://api.weixin.qq.com/sns/oauth2/refresh_token","刷新获取微信token"),
    UrlUserInfo("https://api.weixin.qq.com/sns/userinfo","获取用户信息"),
    WeChatKFState("wechat-kf2-state","redis的key"),
    WeChatKFStateTime("300","redis的key的过期时间(秒)");
    private String code;
    private String msg;

    PublicWeChatEnum(String c, String m) {
      this.code = c;
      this.msg = m;
    }

    public String getCode() {
      return code;
    }
    public String getMsg() {
      return msg;
    }
  }

  enum CacheParamEnum{
    WXOpenID("WX_OpenID_","redis的key"),
    WXOpenIDTime("300","redis的key的过期时间(秒)");
    private String code;
    private String msg;

    CacheParamEnum(String c, String m) {
      this.code = c;
      this.msg = m;
    }

    public String getCode() {
      return code;
    }
    public String getMsg() {
      return msg;
    }
  }

}

<二>扫码登录回调

  // type有web和public两种类型,本文是开放平台,{type}使用的是web
  @ApiOperation(value = "微信登录回调", notes = "微信登录回调")
  @GetMapping("/{type}/wxLoginCallback")
  public Result wxLoginCallback(@PathVariable("type") String type, @RequestParam(name = "code") String code, @RequestParam(name = "state", required = false) String state) throws Exception {
    return thirdLoginService.wxLoginCallback(code, state, type);
  }

涉及的thirdLoginService.wxLoginCallback接口代码如下:

  // 微信登录回调
  @Override
  @Transactional(rollbackFor = Exception.class)
  public Result wxLoginCallback(String code, String state, String type) throws Exception {
    AssertException.isNull(code, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:code is empty,请重新登录!");
    AssertException.isNull(state, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:state is empty,请重新登录!");

    Map userMap = null;
    int regType = RegisterTypeEnum.WX_WEB.getCode();  //枚举:web类型是开放平台,public是公众平台
    if ("web".equals(type)) {
      userMap = thirdGetUserInfoService.wxGetUserInfo(code, state);  //获取用户信息
    } else if ("public".equals(type)) {
      regType = RegisterTypeEnum.WX_MP.getCode();
      userMap = thirdGetUserInfoService.wxPublicGetUserInfo(code, state);  //获取用户信息
    } else {
      AssertException.assertException(AppTipMsgEnum.LOGIN_FAIL.getCode(), "回调类型错误!");
    }

    AssertException.isNullObject(userMap, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败,请重新登录!");
    AssertException.assertException(userMap.get("errcode") != null, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:" + userMap.get("errmsg") + ",请重新登录!");
    AssertException.isNullObject(userMap.get("openid"), AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:openid为空!,请重新登录!");

    // 以下是你自己的代码逻辑操作......
	// 以下是你自己的代码逻辑操作......
	// 以下是你自己的代码逻辑操作......
	
    return Result.Builder.newBuilder(AppTipStatusEmum.SUCCESS_STATUS.getCode(), AppTipMsgEnum.SUCCESS.getText()).setData(objectMap).build();
  }

涉及的thirdGetUserInfoService类的代码如下:

@Service("thirdGetUserInfoService")
public class ThirdGetUserInfoServiceImpl implements ThirdGetUserInfoService {

  // 微信web方式获取用户信息
  @Override
  public Map wxGetUserInfo(String code, String state) throws Exception {
    AssertException.isNull(code, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:code is empty,请重新登录!");
    AssertException.isNull(state, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:state is empty,请重新登录!");

    // 判断state是否合法
    String stateStr = CacheUtil.get(ThirdPartyLoginEnum.WeChatEnum.WeChatKFState.getCode() + state);
    AssertException.assertException(StringUtils.isEmpty(code) || StringUtils.isEmpty(state) || StringUtils.isBlank(stateStr), AppTipMsgEnum.PARAM_NOT_NULL.getCode(), "非法操作,请重新登录!");

    // 用户授权后的code换取token
    Map t_token = WeChatLoginUtil.getAccessToken(code, ThirdPartyLoginEnum.WeChatEnum.AppID.getCode(), ThirdPartyLoginEnum.WeChatEnum.AppSecret.getCode());

    // 判断是否成功获取到了token
    AssertException.isNullObject(t_token, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败,请重新登录!");
    AssertException.assertException(t_token.get("errcode") != null, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:" + t_token.get("errmsg") + ",请重新登录!");
    AssertException.assertException(StringUtils.isEmpty((String) t_token.get("access_token")) || StringUtils.isEmpty((String) t_token.get("openid")), AppTipMsgEnum.PARAM_NOT_NULL.getCode(),
        "access_token拉取失败,请重新登录!");

    // 刷新accesstoken
    Map refreshToken = WeChatLoginUtil.refreshToken(ThirdPartyLoginEnum.WeChatEnum.AppID.getCode(), (String) t_token.get("refresh_token"));
    AssertException.isNullObject(refreshToken, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败,请重新登录!");
    AssertException.assertException(refreshToken.get("errcode") != null, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:" + refreshToken.get("errmsg") + ",请重新登录!");

    // 使用token交换获取用户信息
    String userInfo = WeChatLoginUtil.getUserInfo(refreshToken);

    return JsonUtil.fromJson(userInfo, Map.class);
  }

  // 微信公众号方式获取用户信息
  @Override
  public Map wxPublicGetUserInfo(String code, String state) throws Exception {
    AssertException.isNull(code, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:code is empty,请重新登录!");
    AssertException.isNull(state, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:state is empty,请重新登录!");

    // 判断state是否合法
    String stateStr = CacheUtil.get(ThirdPartyLoginEnum.PublicWeChatEnum.WeChatKFState.getCode() + state);
    AssertException.assertException(StringUtils.isEmpty(code) || StringUtils.isEmpty(state) || StringUtils.isBlank(stateStr), AppTipMsgEnum.PARAM_NOT_NULL.getCode(), "非法操作,请重新登录!");

    // 用户授权后的code换取token
    Map t_token = WeChatLoginUtil.getAccessTokenByPublic(code, ThirdPartyLoginEnum.PublicWeChatEnum.AppID.getCode(), ThirdPartyLoginEnum.PublicWeChatEnum.AppSecret.getCode());

    // 判断是否成功获取到了token
    AssertException.isNullObject(t_token, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败,请重新登录!");
    AssertException.assertException(t_token.get("errcode") != null, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:" + t_token.get("errmsg") + ",请重新登录!");
    AssertException.assertException(StringUtils.isEmpty((String) t_token.get("access_token")) || StringUtils.isEmpty((String) t_token.get("openid")), AppTipMsgEnum.PARAM_NOT_NULL.getCode(),
        "access_token拉取失败,请重新登录!");

    // 刷新accesstoken
    Map refreshToken = WeChatLoginUtil.refreshTokenByPublic(ThirdPartyLoginEnum.PublicWeChatEnum.AppID.getCode(), (String) t_token.get("refresh_token"));
    AssertException.isNullObject(refreshToken, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败,请重新登录!");
    AssertException.assertException(refreshToken.get("errcode") != null, AppTipMsgEnum.LOGIN_FAIL.getCode(), "登录失败:" + refreshToken.get("errmsg") + ",请重新登录!");

    // 使用token交换获取用户信息
    String userInfo = WeChatLoginUtil.getUserInfoByPublic(refreshToken);

    return JsonUtil.fromJson(userInfo, Map.class);
  }
}

至此代码就算完成了,不足之处欢迎指教
由于框架用不明白,不想去理解,感觉配置太麻烦了,花那个时间去研究框架,我都写完了。

公众平台的登录请看另一篇:公众平台–扫描微信二维码,关注后自动登录

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值