微信登录(PC端)

456 阅读3分钟

对于网页的微信扫码登录,首要前提是企业申请的微信开放平台。 微信开放平台地址:open.weixin.qq.com/

微信扫码登录官方文档:developers.weixin.qq.com/doc/oplatfo…

本来想着自己写一个微信登录,然后记录的,哎,微信是又出钱,又需要企业才能认证的,只能拿我在公司做的微信登录做个记录了,以免后期再做,方便使用

效果:

动画.gif

思路: 扫码后通过redirect_uri 跳转到Controller里写业务,拿到openid后。先去这个表查询这个openID有没有关联用户

1、有关联了,就直接签发我们的token,然后带token重定向到我们的应用页完成登录,
2、没有关联,带openID重定向到绑定页, 让用户输入平台账号密码点击绑定,系统验证账号密码通过后将openid保存到用户表,签发我们的token,然后带token重定向到我们的应用页完成登录, 用户下一次扫码登陆就走1的步骤了

1.前端

 /**
 * 第三方登录,微信登录点击事件
 */
wechatHandleClick(){
  const redirect_uri = encodeURIComponent('https://申请微信登录时候的域名/auth/login.html');
  const url = 'https://open.weixin.qq.com/connect/qrconnect?appid=' + this.appid + '&redirect_uri=' + redirect_uri + '&response_type=code&scope=snsapi_login&state=pc#wechat_redirect';
                location.href = url
 }
  1. 后台 redirect_uri 后缀.html是不是很有迷惑性,一看就以为是前端,其实是后台😄

controller:

import com.sinotrans.iot.auth.server.service.biz.service.LoginService;
import com.sinotrans.iot.auth.server.service.biz.wecharOauth2.AccessTokenResult;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import java.awt.*;

@RestController
public class LoginController {

    @Value("${wx.pc.login.success.redirect_uri}")
    private String successPage;
    @Value("${wx.pc.login.bind.redirect_uri}")
    private String bindPage;//绑定页面
    @Autowired
    private LoginService loginService;

    /**
     * 请求access_token
     * @param code
     * @return 成功则跳转应用主页,否则跳转绑定用户页面
     */
    @GetMapping("/login.html")
    public ModelAndView loginHtml(String code,String state) throws Exception {
        AccessTokenResult tokenResult = loginService.pc(code,state);
        if (StringUtils.isNotBlank(tokenResult.getAccess_token())) {
            String spage = successPage + "token=" + tokenResult.getAccess_token();
            return new ModelAndView(new RedirectView(spage));
        }
        String bpage = bindPage + "openid=" + tokenResult.getOpenid();
        return new ModelAndView(new RedirectView(bpage));
    }

    /**
     * 绑定用户微信openid
     * @param userCode 登录账号
     * @param password 登录密码
     * @return token
     */
    @GetMapping(value = "/bindUser",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String bindUser(String openid,String userCode,String password) throws Exception {
        return loginService.bindUser(openid,userCode,password);
    }
}

service:


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sinotrans.framework.mybatis.support.FilterCondition;
import com.sinotrans.iot.auth.server.service.biz.controller.TokenController;
import com.sinotrans.iot.auth.server.service.biz.model.SysUserModel;
import com.sinotrans.iot.auth.server.service.biz.service.LoginService;
import com.sinotrans.iot.auth.server.service.biz.service.SysUserManager;
import com.sinotrans.iot.auth.server.service.biz.vo.TokenPasswordVo;
import com.sinotrans.iot.auth.server.service.biz.wecharOauth2.AccessTokenResult;
import com.sinotrans.iot.auth.server.service.util.HttpUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class LoginServiceImpl implements LoginService {
    private Logger log = LoggerFactory.getLogger(getClass());
    @Value("${wx.open.appid}")
    private String wxOpenAppid;
    @Value("${wx.open.appsecret}")
    private String wxOpenAppsecret;

    @Autowired
    private SysUserManager sysUserManager;
    @Autowired
    private TokenController tokenController;

    /**
     * pc 端登录
     *
     * @param code 微信扫码后返回的code
     * 拿到openid后。先去用户表查询这个openID有没有关联用户,
     * 1、有关联了,就直接签发我们的token,然后带token重定向到我们的应用页完成登录,
     * 2、没有关联,带openID重定向到绑定页(新增的页面), 让用户输入平台账号密码点击绑定,
     *    然后系统验证账号密码通过将自动关联用户的openid,然后签发我们的token,
     *    然后带token重定向到我们的应用页完成登录,用户下一次扫码登陆就走1的步骤了
     */
    @Override
    public AccessTokenResult pc(String code,String state) throws Exception {
        String tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
        String param = "appid=" + wxOpenAppid + "&secret=" + wxOpenAppsecret + "&code=" + code
                + "&state=" + state + "&grant_type=authorization_code";
        String strResult = HttpUtils.sendGet(tokenUrl, param);
        AccessTokenResult resule = JSONObject.parseObject(strResult, AccessTokenResult.class);
        if (StringUtils.isBlank(resule.getOpenid())) {
            throw new RuntimeException(JSON.toJSONString(resule));
        }
        List<FilterCondition> conditionList = new ArrayList<>();
        conditionList.add(new FilterCondition("openId", resule.getOpenid(), "="));
        List<SysUserModel> user = sysUserManager.getUser(conditionList);
        if (!user.isEmpty()) {
            resule.setAccess_token(getToken(user.get(0)));
        }else {
            resule.setAccess_token("");
        }
        return resule;
    }

    /**
     * 绑定用户
     * @param userCode
     * @param password
     * @return
     * @throws Exception
     */
    @Override
    public String bindUser(String openid,String userCode, String password) throws Exception {
        String token = "";
        List<FilterCondition> conditionList = new ArrayList<>();
        conditionList.add(new FilterCondition("code", userCode, "="));
        conditionList.add(new FilterCondition("pwd", password, "="));
        List<SysUserModel> user = sysUserManager.getUser(conditionList);
        if(!user.isEmpty()){
            SysUserModel sysUserModel = user.get(0);
            sysUserModel.setOpenId(openid);
            sysUserManager.save(sysUserModel);//绑定openid

            token = getToken(sysUserModel);//获取token
        }
        return token;
    }

    /**
     * 从现有方法中获取token
     * @param user
     * @return
     * @throws Exception
     */
    private String getToken(SysUserModel user) throws Exception {
        String token;
        TokenPasswordVo tokenPasswordVo = new TokenPasswordVo();
        tokenPasswordVo.setUsername(user.getCode());
        tokenPasswordVo.setPassword(user.getPwd());
        Map<String, Object> o = (Map<String, Object>)tokenController.v2login(null, tokenPasswordVo);
        token = o.get("access_token").toString();
        return token;
    }
}

model:


public class AccessTokenResult {
	
	// 接口调用凭证
	private String access_token;
	
	// access_token接口调用凭证超时时间,单位(秒)
	private Long expires_in;
	
	// 用户刷新access_token
	private String refresh_token;
	
	// 授权用户唯一标识
	private String openid;
	
	// 用户授权的作用域,使用逗号(,)分隔
	private String scope;
	
	// 用户授权的作用域,使用逗号(,)分隔
	private String unionid;
	
	// 错误码
	private Long errcode;
	
	// 错误消息
	private String errmsg;

	public String getAccess_token() {
		return access_token;
	}

	public void setAccess_token(String access_token) {
		this.access_token = access_token;
	}

	public Long getExpires_in() {
		return expires_in;
	}

	public void setExpires_in(Long expires_in) {
		this.expires_in = expires_in;
	}

	public String getRefresh_token() {
		return refresh_token;
	}

	public void setRefresh_token(String refresh_token) {
		this.refresh_token = refresh_token;
	}

	public String getOpenid() {
		return openid;
	}

	public void setOpenid(String openid) {
		this.openid = openid;
	}

	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getUnionid() {
		return unionid;
	}

	public void setUnionid(String unionid) {
		this.unionid = unionid;
	}

	public Long getErrcode() {
		return errcode;
	}

	public void setErrcode(Long errcode) {
		this.errcode = errcode;
	}

	public String getErrmsg() {
		return errmsg;
	}

	public void setErrmsg(String errmsg) {
		this.errmsg = errmsg;
	}

}