SpringBoot

Spring boot + Vue 微信第三方登录实践

2020-06-29  本文已影响0人  Epat

1. 流程图

第三方登录流程图

微信登录流程如下:

  1. 点击微信登录,新开窗口,跳转到微信扫码页面
  2. 用户扫码登录,新开窗口跳转到后台微信登录接口
  3. 后台判断用户是否成功登录,将新开窗口重定向到前台微信登录处理页面
  4. 微信登录处理页面会关闭新开窗口,判断用户是否成功登录,如果用户成功登录,跳转首页,如果用户登录失败,跳转注册页面

2. 前端代码核心逻辑实现

第一步 微信登录跳转逻辑

  import URL from 'url-parse'
  const WECHAT_BASE_URL = 'https://open.weixin.qq.com/connect/qrconnect'
  const appId = "xxxxxx"
  const redirectUri = "http://server:ip/wxLogin"
  const responseType = "code"
  const scope = "snsapi_login"
  const wechatUrl = new URL(WECHAT_BASE_URL)
  const windowHeight = window.screen.availHeight
  const windowWidth = window.screen.availWidth
  const height = 500
  const width = 500
  // 构建微信扫码页面链接
  wechatUrl.set('query', {
    appid: appId,
    redirect_uri: encodeURI(redirectUri),
    response_type: responseType,
    scope,
    state
  })
  wechatUrl.set('hash', 'wechat_redirect')
  // 新窗口打开微信扫码页面
  window.open(
      wechatUrl.toString(),
      '_blank',
      `toolbar=no,directories=no,status=no,menubar=no,height=${height},width=${width},top=${(windowHeight - height) / 2},left=${(windowWidth - width) / 2}`
    )

第二步 实现后端微信登录回调页面

  1. 在App.vue中新增微信登录回调方法
export default {
  mounted () {
    window.globalVue.$on('wechatLoginCallBack', function(result) {
      console.log('监听到事件')
      if (result.code === 200) {
        // 微信登录成功
      } else {
        // 微信登录失败,用户不存在
      }
   })
  }
}
  1. 编写后台微信登录回调页面
<template>
  <div></div>
</template>

<script>
// 这是一个空页面,专门用来处理微信登录成功回调 访问路径为 /wechat/callback
export default {
  mounted() {
    this.init()
  },
  methods: {
    init() {
      const code = parseInt(this.$route.query.code)
      const token = this.$route.query.token
      const message = this.$route.query.message
      // 调用微信登录回调方法
       window.opener.globalVue.$emit('wechatLoginCallBack', {
         code,
         token,
         message
       })
       this.$nextTick(() => {
         self.close()
       })
    }
  }
}
</script>

第三步 实现后台微信登录处理接口

实现微信登录Controller

@RequestMapping("/wechatOpenPlatform")
public class WechatOpenPlatformController{
    @Autowired
    WechatOauthService wechatOauthService;

    @GetMapping("login")
    @ApiOperation(value = "微信网页登录", notes = "微信网页登录")
    public void login(@PathVariable String region, @NotNull(message = "微信登录参数错误") String code, HttpServletResponse response) {
        wechatOauthService.wechatLogin(code, response);
    }
}

实现微信登录service实现

public interface WechatOauthService {

    /**
     * 微信网页登录
     * 
     * @param oauth2Handler
     * @param callbackUrl
     * @param authTokenForm
     * @param response
     */
    void wechatLogin(String code,
        HttpServletResponse response);

}
@Service
public class WechatOauthServiceImpl implements WechatOauthService {
  private static String callBackUrl = "http://www.xxxx.com/#/wechat/callback";
  private static String openAppId= "xxxxx";
  private static String openSecret= "xxxx";

  @Autowired
  UserService userService;

  @Autowired
  AutowireCapableBeanFactory autowireCapableBeanFactory;

  @Override
  public void wechatLogin (String code, HttpServletResponse response) {
    WechatHandler wechatHandler= new WechatHandler(openAppId, openSecret);
    // 实现容器外bean注入
    autowireCapableBeanFactory.autowireBean(wechatHandler);
    // 获取用户token
    AuthTokenVo authTokenVo = wechatHandler.fetchToken(code);
    // 根据token获取用户信息
    WechatUserVo wechatUserVo = wechatHandler.fetchUserInfo(authTokenVo);
    // 根据unionId判断用户是否存在
    UserMo userMo = userService.selectUserByUnionId(wechatUserVo.getUnionId());
    if (userMo == null) {
    // 登录失败
    response.sendRedirect(callBackUrl + "?code=500&token=" + wechatUserVo.getUnionId());
    }
    // 调用登录方法,写入cookie
    userService.login(userMo);
    // 登录成功
    response.sendRedirect(callBackUrl + "?code=200");
  }
}

// 调用微信接口获取微信信息处理类

public class WechatHandler {

   /**
     * 应用唯一标识
     */
    private String appId;

    /**
     * 应用密钥
     */
    private String secret;

    /**
     * 请求方法
     */
    @Resource
    RestTemplate restTemplate;

    public WechatHandler(String appId, String secret) {
        this.appId = appId;
        this.secret = secret;
    }

    private final static String BASE_URL = "https://api.weixin.qq.com";

    private final static String FETCH_TOKEN_GRANT_TYPE = "authorization_code";

    private final static String TOKEN_URL =
        BASE_URL + "/sns/oauth2/access_token?appid={appId}&secret={secret}&code={code}&grant_type={grantType}";

    private final static String USER_INFO_URL = BASE_URL + "/sns/userinfo?access_token={accessToken}&openid={openId}";

    @Override
    public AuthTokenVo fetchToken(AuthTokenForm authTokenForm) {
        Map<String, String> query = new HashMap<>();
        query.put("appId", getAppId());
        query.put("secret", getSecret());
        query.put("code", authTokenForm.getCode());
        query.put("grantType", FETCH_TOKEN_GRANT_TYPE);
        String result = restTemplate.getForObject(TOKEN_URL, String.class, query);
        JSONObject jsonObject = JSON.parseObject(result);
        if (jsonObject.getInteger("errcode") != null) {
            throw new BusinessException("获取TOKEN失败");
        }
        AuthTokenVo authTokenVo = new AuthTokenVo(jsonObject);
        return authTokenVo;
    }

    @Override
    public AuthTokenVo refreshToken(AuthRefreshTokenForm authRefreshTokenForm) {
        return null;
    }

    @Override
    public Object fetchUserInfo(AuthTokenVo authTokenVo) {
        Map<String, String> query = new HashMap<>();
        query.put("accessToken", authTokenVo.getAccessToken());
        query.put("openId", authTokenVo.getOpenId());
        String result = restTemplate.getForObject(USER_INFO_URL, String.class, query);
        JSONObject jsonObject = JSON.parseObject(result);
        if (jsonObject.getInteger("errcode") != null) {
            throw new BusinessException("获取用户信息失败");
        }
        WechatUserVo wechatUserVo = new WechatUserVo(jsonObject);
        return wechatUserVo;
    }

}

微信用户实体类

@Data
@NoArgsConstructor
public class WechatUserVo {

    /**
     * OPEN_ID
     */
    private String openId;

    /**
     * 唯一标识
     */
    private String unionId;

    /**
     * 昵称
     */
    private String nickName;

    /**
     * 性别
     */
    private Integer sex;

    /**
     * 省份
     */
    private String province;

    /**
     * 城市
     */
    private String city;

    /**
     * 国家
     */
    private String country;

    /**
     * 头像
     */
    private String headImgUrl;

    /**
     * 特权信息
     */
    private String privilege;

    public WechatUserVo(JSONObject jsonObject) {
        this.unionId = jsonObject.getString("unionid");
        this.openId = jsonObject.getString("openid");
        this.nickName = jsonObject.getString("nickname");
        this.sex = jsonObject.getInteger("sex");
        this.province = jsonObject.getString("province");
        this.city = jsonObject.getString("city");
        this.country = jsonObject.getString("country");
        this.headImgUrl = jsonObject.getString("headimgurl");
        this.privilege = jsonObject.getString("privilege");
    }
}
上一篇 下一篇

猜你喜欢

热点阅读