Based on Vue+SpringCloudAlibaba Microservice E-commerce Project Actual Combat-Building Member Service-010: Quickly Integrate WeChat Joint Login Based on the Strategy Model

010: Quickly integrate WeChat joint login based on the strategy model

1 Integrated WeChat joint login effect demonstration

Today's Course Task

  1. Principles of WeChat Official Account Development Authorization and Joint Login
  2. How to quickly integrate WeChat joint login based on the strategy model
  3. Token association based on user authorization openId information
  4. Possible problems with the front-end and back-end separation architecture model

2 Principles of WeChat Joint Login to Obtain User Information

WeChat authorization link login follows the standard oauth2.0 protocol

  1. Generate authorization link (user access) appId, callback address
  2. Obtain accessToken and openId according to the authorization code
  3. According to openId, WeChat user information (WeChat name, picture, address, etc.) can be obtained

WeChat open document address:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

Reference link (please open this link in the WeChat client to experience): The
scope is 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 Pay special
attention to: the redirect callback redirect_uri should use the https link to ensure the security of the authorization code.

Test effect:

Insert picture description here

4 Obtain user's basic information according to openid

Step 2: Exchange code for webpage authorization access_token
First of all, please note that the code exchanged here is a special webpage authorization access_token, which is different from the access_token in basic support (this access_token is used to call other interfaces). The official account can obtain webpage authorization access_token through the following interface. If the scope of the webpage authorization is snsapi_base, then at the same time that the webpage authorization access_token is obtained in this step, the openid is also obtained, and the snsapi_base-style webpage authorization process ends here.
Pay special attention to: Since the secret of the official account and the obtained access_token have a very high security level, they must only be stored on the server and not allowed to be transmitted to the client. Subsequent steps such as refreshing access_token and obtaining user information through access_token must also be initiated from the server.
Request method After
obtaining the code, request the following link to obtain access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

Step 4: Pull user information (the scope is snsapi_userinfo required)
If the authorization scope of the web page is snsapi_userinfo, then the developer can pull user information through access_token and openid.
Request method
http: GET (please use https protocol)
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

Test effect:

Insert picture description here

5 Quickly integrate WeChat joint login based on the strategy model

Insert data into the database

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);

WeChat login policy implementation class

@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

Test effect:

Insert picture description here

6 The design principle of vue integrated WeChat joint login

The associated page needs to pass the token token

  1. First parse the corresponding openId from redis according to the token
  2. If the openId has been associated with an account, you can directly log in automatically, return the user's token to the client, and vue directly jumps to the home page;
  3. If the openId has not been associated with an account, jump to the page and choose to associate a new account or an existing account. When you select to associate an existing account, the openToken will be passed when logging in, and the database will update the user's openId field.

7 The principle of quick login based on 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);
    }
}

Test effect

Insert picture description here