Login issue-single sign-on (SSO), WeChat scan login

This article mainly explains the login problem of the online education system.
Main introduction-single sign-on concept, WeChat scan login (Java backend)

Article Directory

1. Single sign-on

1.1 Introduction

  • Single Sign On (Single Sign On-SSO)
  • In multiple application systems, you only need to log in once to access other mutually trusted application systems

1.2 Three common single sign-on methods

1.2.1 Implementation of session broadcast mechanism

  1. After the login is successful, put the user data in the session;
  2. Determine whether to log in, get data from the session, you can get the login

Log in to any module in the project, after logging in, put the data in two places

 redis:在 key 生成唯一随机值(ip、用户id等等);在 value 中存储用户数据
 cookie:把 redis 里面生成的 key 值放到 cookie 里面

Visit other modules in the project, send the request with a cookie, and get the redis value

 把 cookie 获取值,到 redis 进行查询, 根据 key 进行查询,如果查询到数据就是登录

1.2.3 Implementation using token

Log in to a module in the project. After logging in, a string is generated according to certain rules, and the user information after logging in is included in the generated string, and the string is returned

 可以把字符串通过 cookie 返回;

Then visit other modules of the project, each time you visit with a generated string in the address bar, you can get user information based on the string in the address bar

1.2.4 JWT

  • token is a string generated according to certain rules, including user information
  • What is the rule, not necessarily
  • Generally adopt official rules (JWT)

The JWT generated string consists of three parts:

  1. JWT header information;
  2. Payload, including subject information (user information);
  3. Signature hash (anti-counterfeiting mark)

2. Log in

  • Implementation interface

2.1 Ordinary login

  • Get login mobile phone number and password
  • Determine whether the mobile phone number and password are empty
  • Determine whether the phone number is correct-compare with the phone number in the database
  • Determine whether the password seems to be correct-encrypt the entered password and compare it with the database password
  • Use JWT tool class to generate and return token
    public String login(UcenterMember member) {
        String mobile = member.getMobile();
        String password = member.getPassword();

        if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)) {
            throw new GuliException(20001,"登录失败");

        QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
        UcenterMember mobileMember = baseMapper.selectOne(wrapper);
        if(mobileMember == null) {//没有这个手机号
            throw new GuliException(20001,"登录失败");

        //加密方式 MD5
        if(!MD5.encrypt(password).equals(mobileMember.getPassword())) {
            throw new GuliException(20001,"登录失败");

        String jwtToken = JwtUtils.getJwtToken(mobileMember.getId(), mobileMember.getNickname());
        return jwtToken;

2.2 WeChat scan login

2.2.1 OAuth2

  1. OAuth2 is a solution to specific problems
  2. Mainly solve two problems: 1.Open system authorization 2.Distributed access problem

Authorization method between open systems:

  • Password username copy,
  • Universal developer key (master key),
  • Way token

Distributed access (single sign-on)

1. 登陆成功之后,按照一定的规则生成字符串,字符串包含用户信息
2. 把生成的字符串通过路径传播,或者cookie
3. 后面再发送请求的时候,每次带着字符串进行发送;获取字符串,从字符串中获取用户信息登录

OAuth2 solution: token mechanism, according to certain rules to generate a string, the string contains user information

2.2.2 Preparation

In short: get app_id with app_secret

# 微信开放平台 -- appid
# 微信开放平台 -- appsecret
# 微信开放平台 -- 重定向url

2.2.3 Generate WeChat Scan QR Code

  • Directly request WeChat to provide a fixed address (splicing parameters to the back of the address)
  • Return address (the QR code is in the address)
    // 生成微信扫描二维码
    public String getWxCode() {
//        String url = "https://open.weixin.qq.com/" +
//                "connect/qrconnect?appid="+ ConstantWxUtils.WX_OPEN_APP_ID+"&response_type=code";

        // 微信开放平台授权baseUrl  %s相当于?代表占位符
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +

        String redirectUrl = ConstantWxUtils.WX_OPEN_REDIRECT_URL;
        try {
            redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
        }catch(Exception e) {

        String url = String.format(

        return "redirect:"+url;

2.2.4 Scan the QR code

Steps :

After scanning, execute the local callback method, and pass two values ​​(state-passed as is) when jumping (code-similar to mobile phone verification code);

Get the code of the first step, request WeChat to provide a fixed address, and get two values;

  1. access_token: Access credentials
  2. openid: A unique identifier for each WeChat

Get the access_token and openid, and then request a WeChat fixed address, you can finally get the information of the person scanned by WeChat

    private UcenterMemberService memberService;

    //2 获取扫描人信息,添加数据
    public String callback(String code, String state) {
        try {
            //1 获取code值,临时票据,类似于验证码
            //2 拿着code请求 微信固定的地址,得到两个值 accsess_token 和 openid
            String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                    "?appid=%s" +
                    "&secret=%s" +
                    "&code=%s" +
            //拼接三个参数 :id  秘钥 和 code值
            String accessTokenUrl = String.format(
            //请求这个拼接好的地址,得到返回两个值 accsess_token 和 openid
            String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);

            //从accessTokenInfo字符串获取出来两个值 accsess_token 和 openid
            //使用json转换工具 Gson
            Gson gson = new Gson();
            HashMap mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class);
            String access_token = (String)mapAccessToken.get("access_token");
            String openid = (String)mapAccessToken.get("openid");

            UcenterMember member = memberService.getOpenIdMember(openid);
            if(member == null) {//memeber是空,表没有相同微信数据,进行添加

                //3 拿着得到accsess_token 和 openid,再去请求微信提供固定的地址,获取到扫描人信息
                String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                        "?access_token=%s" +
                String userInfoUrl = String.format(
                String userInfo = HttpClientUtils.get(userInfoUrl);
                HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
                String nickname = (String)userInfoMap.get("nickname");//昵称
                String headimgurl = (String)userInfoMap.get("headimgurl");//头像

                member = new UcenterMember();
                memberService.save(member);   // 保存新用户

            String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());
            return "redirect:http://localhost:3000?token="+jwtToken;
        }catch(Exception e) {
            throw new GuliException(20001,"登录失败");