基于Vue+SpringCloudAlibaba微服务电商项目实战-构建会员服务-010:基于策略模式快速整合微信联合登录

1 整合微信联合登录效果演示

今日课程任务

  1. 微信公众号开发授权联合登录的原理
  2. 基于策略模式如何快速整合微信联合登录
  3. 基于用户授权的令牌关联openId信息
  4. 前后端分离架构模式可能会存在的问题

2 微信联合登录获取用户信息原理

微信授权链接登录 遵循规范oauth2.0协议

  1. 生成授权链接(用户访问) appId、回调地址
  2. 根据授权code获取accessToken和openId
  3. 根据openId可以获取微信用户信息(微信名称、图片、地址等)

3 生成微信oatuh2.0授权链接地址

微信开放文档地址:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

参考链接(请在微信客户端中打开此链接体验):
scope为snsapi_userinfo
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
尤其注意:跳转回调redirect_uri,应当使用https链接来确保授权code的安全性。

测试效果:
在这里插入图片描述

4 根据openid获取用户的基本信息

第二步:通过code换取网页授权access_token
首先请注意,这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。
尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。
请求方法
获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

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

测试效果:
在这里插入图片描述

5 基于策略模式快速整合微信联合登录

数据库插入数据

INSERT INTO `meite_member`.`meite_union_login`(`id`, `union_name`, `union_public_id`, `union_bean_id`, `app_id`, `app_key`, `redirect_uri`, `request_address`, `is_availability`) VALUES (2, '腾讯微信联合登陆', 'mayikt_weixin', 'weiXinUnionLoginStrategy', 'wx84fa688175f78964', '1451cd74xxxe99ff3a1f1e', 'http://www.itmayiedu.com:7070/login/oauth/callback?unionPublicId=mayikt_weixin', 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx84fa688175f78964&redirect_uri=http://www.itmayiedu.com:7070/login/oauth/callback?unionPublicId=mayikt_weixin&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect', 1);

微信登录策略实现类

@Component
public class WeiXinUnionLoginStrategy implements UnionLoginStrategy {
    @Value("${mayikt.login.wx.accesstoken}")
    private String weixinAccessTokenAddres;
    @Autowired
    private UserMapper userMapper;

    @Override
    public String unionLoginCallback(HttpServletRequest request, UnionLoginDO unionLoginDo) {
        String code = request.getParameter("code");
        if (StringUtils.isEmpty(code)) {
            return null;
        }
        // 根据授权码获取accessToken和openid
        String newWeixinAccessTokenAddres = weixinAccessTokenAddres.replace("APPID", unionLoginDo.getAppId() + "").replace("SECRET",
                unionLoginDo.getAppKey()).replace("CODE", code);
        JSONObject accessTokenResult = HttpClientUtils.httpGet(newWeixinAccessTokenAddres);
        if (accessTokenResult == null) {
            return null;
        }
        boolean errcode = accessTokenResult.containsKey("errcode");
        if (errcode) {
            return null;
        }
        // 获取openid
        String openid = accessTokenResult.getString("openid");
        if (StringUtils.isEmpty(openid)) {
            return null;
        }
        return openid;
    }
}

bootstrap.yml

mayikt:
  login:
    wx:
      accesstoken: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

测试效果:
在这里插入图片描述

6 vue整合微信联合登录的设计原理

关联页面需要传递token令牌

  1. 先根据令牌从redis中解析出对应的openId
  2. 如果该openId关联过账户,直接实现自动登录,返回用户的token给客户端,vue直接跳转到首页页面;
  3. 如果该openId没有关联过账户,跳转到页面选择关联新账号或者已有账号,当选择关联已有账号,登录的时候会传递该openToken,数据库会更新该用户openId字段。

7 基于openidToken实现快速登录原理

@Api(tags = "基于OpenIdToken登录")
public interface MemberOpenIdTokenLogin {

    @GetMapping("/openIdToken")
    BaseResponse<JSONObject> openIdLoginToken(@RequestParam("openIdToken") String openToken);
}
@RestController
public class MemberOpenIdTokenLoginImpl extends BaseApiService implements MemberOpenIdTokenLogin {
    @Autowired
    private TokenUtil tokenUtil;

    @Value("${mayikt.login.token.prefix}")
    private String loginTokenPrefix;
    @Autowired
    private UnionLoginMapper unionLoginMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public BaseResponse<JSONObject> openIdLoginToken(String openToken) {
        if (StringUtils.isEmpty(openToken)) {
            return null;
        }
        // 1.根据openToken 获取真实openid
        String tokenValue = tokenUtil.getTokenValue(openToken);
        if (StringUtils.isEmpty(tokenValue)) {
            return setResultError("流程已经失效或者token错误");
        }
        // 2.根据openid 查询是否关联
        JSONObject jsonObject = JSONObject.parseObject(tokenValue);

        String unionPublicId = jsonObject.getString("unionPublicId");
        // 3.根据该渠道id查询bean的id,从容器中获取
        // 根据渠道id查询 联合基本信息  在缓存存一份
        UnionLoginDO unionLoginDo = unionLoginMapper.selectByUnionLoginId(unionPublicId);
        if (unionLoginDo == null) {
            return setResultError("该渠道可能已经关闭或者不存在");
        }
        String unionBeanId = unionLoginDo.getUnionBeanId();
        UnionLoginStrategy unionLoginStrategy = SpringContextUtils.
                getBean(unionBeanId, UnionLoginStrategy.class);
        if (unionLoginStrategy == null) {
            return setResultError("没有查询到该策略");
        }
        String openid = jsonObject.getString("openId");
//        UserDO userDO = null;
//        switch (unionPublicId) {
//            case "mayikt_qq":
//                userDO = userMapper.selectByQQOpenId(openid);
//            case "mayikt_weixin":
//                userDO = userMapper.selectByOpenId(openid);
//        }
        // 策略模式重构,以上两种场景方法分别放子类中实现
        UserDO userDo = unionLoginStrategy.getDbOpenId(openid);
        if (userDo == null) {
            return setResultError("当前用户没有关联,应该跳转到关联页面");
        }
        // 3.如果已经关联,自动帮助实现登录
        //获取userId 这里可以和MemberLoginServiceImpl共同业务逻辑重构一个manage
        Long userId = userDo.getUserId();
        String userToken = tokenUtil.createToken(loginTokenPrefix, userId + "");
        JSONObject data = new JSONObject();
        data.put("userToken", userToken);
        return setResultSuccess(data);
    }
}

测试效果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值