Wechat applet login authorization development

Keywords: Mini Program wechat

I. understanding development tools

Development interface description

1. wxml is mainly used to layout components (equivalent to building structure)
For example, how many floors are there in the building, how many rooms are there on each floor, and what equipment are there
2. wxss mainly determines the display style (determines the style of the building)
Such as: color, size, width and height
3. js is mainly used to process logic (determine what functions the building has)
For example, the building has elevator function, air conditioning, refrigeration, lighting, water supply and power supply, mainly for the operation of the building.

Secondary interface

Professional interpretation of official reference documents


reference resources: Add link description

wx.getUserProfile(Object object) to obtain user information

Get user information. It can only be called after the page generates a click event (for example, in the callback of bindtap on button). Each request will pop up an authorization window. After the user agrees, it will return userInfo

  • Front end xml page standalone event binding wx.getUserProfile
<!-- Bind login event without user information -->
<button wx:if="{{!userInfo}}" bindtap="login">Authorized login</button>
<view wx:else class="root">
  <image class="touxiang" src="{{userInfo.avatarUrl}}"></image>
  <text class="nicheng">{{userInfo.nickName}}</text>
  <button bindtap="loginOut">Log out</button>
</view>
  • Access to user information interface
Page({
  data: {
    userInfo: ''
  },
  onLoad() {
    let user = wx.getStorageSync('user')
    console.log('Enter applet index Page fetch cache', user)
    this.setData({
      userInfo: user
    })
  },

  // Authorized login
  login() {
    wx.getUserProfile({
      desc: 'You must authorize it before you can continue to use it',
      success: res => {
        let user = res.userInfo
        // Cache user information locally
        wx.setStorageSync('user', user)
        console.log("User information", user)
        this.setData({
          userInfo: user
        })
      },
      fail: res => {
        console.log('privilege grant failed', res)
      }
    })
  },
  // Log out
  loginOut() {
    this.setData({
      userInfo: ''
    })
    wx.setStorageSync('user', null)
  }
})


wx.login(Object object) get code

1. Call this interface to obtain the login Certificate (code) in exchange for the user login status information, including the user's unique ID (openid) and the session_key of this login
2. Then we take this code to our server in exchange for user openid and session_key
3.code is temporary and valid for 5 minutes,
4. Not every time wx.login updates the session_key,session_ The validity of the key will not be told to the developer by wechat. You can customize the validity of the login status session, or update the session stored on the server through the auth.code2Session interface_ key
Reference address
5... openId is unchanged. If a bad person requests with someone else's openId, there will be impersonation. Therefore, we suggest that developers can generate a valid third-party session in the background to log in. Users need to update every other period of time to ensure the security of data.

  // Authorized login
  login() {
    wx.getUserProfile({
      desc: 'You must authorize it before you can continue to use it',
      success: res => {
        let user = res.userInfo
        // Cache user information locally
        wx.setStorageSync('user', user)
        console.log("User information", user)
        this.setData({
          userInfo: user
        })
      // Get code
        wx.login({
          success (res) {
            if (res.code) {
              //Initiate network request
              // wx.request({
              //   url: 'https://example.com/onLogin',
              //   data: {
              //     code: res.code
              //   }
              // })
              console.log("Get login credentials:",res.code)
            } else {
              console.log('Login failed!' + res.errMsg)
            }
          }
        })

      },
      fail: res => {
        console.log('privilege grant failed', res)
      }
    })
   
  }

auth.code2Session get appID

Obtain the temporary login certificate code through the wx.login interface and transfer it to the developer server. Call this interface to complete the login process
Login address:
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code




reference resources: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

2. how to get AppId and AppSecret of WeChat Applet / WeChat official account

Front end complete code

index.js

Page({
  data: {
    userInfo: ''
  },
  onLoad() {
    let user = wx.getStorageSync('user')
    console.log('Enter applet index Page fetch cache', user)
    this.setData({
      userInfo: user
    })
  },

  // Authorized login
  login() {
    wx.getUserProfile({
      desc: 'You must authorize it before you can continue to use it',
      success: res => {
        let user = res.userInfo
        // Cache user information locally
        wx.setStorageSync('user', user)
        console.log("User information is:", user)
        this.setData({
          userInfo: user
        })
      // Get code
        wx.login({
          success (res) {
            if (res.code) {
              console.log("code Yes:", res.code)
              console.log("The user's Avatar is:", user.avatarUrl)
              console.log("The user's nickname is:", user.nickName)
              console.log("User gender 1 is male:", user.gender)
              //Initiate network request
              wx.request({
                method:'POST',
                header: {
                  'content-type': 'application/json'
                },
                url: 'http://127.0.0.1:19092/wechat/login',
                data: {
                  code: res.code,
                  ninck: user.nickName,
                  avaurl: user.avatarUrl,
                  sex: user.gender

                },
                dataType:'json',
                success: function(msg) {
                  if (msg) {
                
                  console.log('msg Is:' +JSON.stringify(msg));
                  console.log('Obtained user token Is:' + msg.data.token);
                  //The token can be saved to the local cache, and the front and back ends carry the token for interaction
                  wx.setStorageSync('token', msg.data.token);
                  } else {
                    console.log('Unable to get data'+msg);
                  }
                  
                }
              })
              
            } else {
              console.log('Login failed!' + res.errMsg)
            }
          }
        })

      },
      fail: res => {
        console.log('privilege grant failed', res)
      }
    })
   
  },
  // Log out
  loginOut() {
    this.setData({
      userInfo: ''
    })
    wx.setStorageSync('user', null)
    wx.setStorageSync('token', null)
  }
})

index.xml

<!-- Bind login event without user information -->
<button wx:if="{{!userInfo}}" bindtap="login">Authorized login</button>
<view wx:else class="root">
  <image class="touxiang" src="{{userInfo.avatarUrl}}"></image>
  <text class="nicheng">{{userInfo.nickName}}</text>
  <button bindtap="loginOut">Log out</button>
</view>

The back-end interface obtains the openid and session key session_key

session_ The key should not be passed to the applet. A session ID should be customized in combination with openid phase I and returned to the applet to identify the login status of the client applet

!!!!! session_key is the identity certificate issued by the wechat server to the developer server. The developer can use session_key requests other interfaces of wechat server to obtain some other information. You can see that session_ The key should not be leaked or distributed to the front end of the applet.

1. Control layer

/**
 * @author an
 * @version 1.0
 * @date 2021/9/19 17:34
 */
@RestController
@RequestMapping("/wechat")
public class WeiXingLoginController {

    private static final Logger logger = LoggerFactory.getLogger(WeiXingLoginController.class);
    @Autowired
    private WeiXingLoginServer weiXingLoginServer;

    @PostMapping("/login")
    public ResponseEntity<UserMsgDTO> wxLogin(@RequestBody UserMsgDTO userMsgDTO) {
        if (StringUtils.isNotBlank(userMsgDTO.getCode())) {
            logger.info("Logon Credentials  code={}", userMsgDTO.getCode());
        }

        if (ObjectUtils.isEmpty(userMsgDTO)) {
            throw new MyException(StatusCode.ERROR, "Code is not null", "wxLogin");
        }

        UserMsgDTO userDTO = weiXingLoginServer.weChatMiNiLogin(userMsgDTO);
        logger.info("userDTO={}", userDTO);
        return ResponseEntity.ok(userDTO);
    }


}

2. Presentation layer

**
 * @author an
 * @version 1.0
 * @date 2021/9/19 17:46
 */
@Service
public class WeiXingLoginServer {

    private static final Logger logger = LoggerFactory.getLogger(WeiXingLoginServer.class);

    @Value("${wx.appid}")
    private String appid;
    @Value("${wx.secret}")
    private String secret;
    @Value("${wx.grant_type}")
    private String grantType;
    @Value("${wx.url}")
    private String url;

    public UserMsgDTO weChatMiNiLogin(UserMsgDTO userMsgDTO) {

        Map<String, String> param = new HashMap<>();
        param.put("appid", appid);
        param.put("secret", secret);
        param.put("js_code", userMsgDTO.getCode());
        param.put("grant_type", grantType);
        //Request to get the session returned by the applet service_ id
        //GET https://api.weixin.qq.com/sns/jscode2session?
        // appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
        logger.info("Wechat request parameters are: url={},param={}", url, param);
        String wxResult = HttpClientUtil.doGet(url, param);


        if (StringUtils.isBlank(wxResult)) {

            throw new MyException(StatusCode.ERROR, "Cannot get appid");

        }
        //Parse the corresponding content (convert to json object)
        JSONObject jsonObject = JSONObject.parseObject(wxResult);

        String openid = jsonObject.getString("openid");//User unique ID
        String session_key = jsonObject.getString("session_key");Get session key( session_key)
        logger.info("Results returned by wechat: jsonObject={}", jsonObject);
        //
        String token = UUID.randomUUID().toString();

        RedisUtils.hPut(token, "openid", openid);
        RedisUtils.hPut(token, "session_key", session_key);
        RedisUtils.setHashKeyTime(token, 60*60, TimeUnit.SECONDS);
        logger.info("Returned token={}", token);


        UserMsgDTO userMsgDTORsp = new UserMsgDTO();
        userMsgDTORsp.setToken(token);

        return userMsgDTORsp;


    }


}

3.pojo

/**
 * @author an
 * @version 1.0
 * @date 2021/9/19 17:41
 */
@Getter
@Setter
public class UserMsgDTO implements Serializable {

    private String id;

    private String customerName;

    private String mobilePhone;

    private String avatarId;

    private String fromSource;

    private String code;

    private String nickName;

    private String avatarUrl;
    //1 is male and 2 is female
    private String gender;
    //session_key
    private String session_key;
    private String token;


}

4. Tools and configuration files

Coordinate dependence

   <!-- httpClient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>

Profile:

server:
  port: 19092
spring:
  application:
    name: weixing-login
  redis:
    host: 127.0.0.1
    port: 6379

wx:
  appid: "wx33244c4d8d4ec025"  # Applet appId
  secret: "05465b97898928fd80447aac89a24c32"   #Applet appSecret
  grant_type: "authorization_code"  #Authorization type. Only authorization_code is required here
  url: "https://api.weixin.qq.com/sns/jscode2session "# get the request address of appID

HttpClientUtil :

public class HttpClientUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

    //REQUEST GET
    public static String doGet(String url, Map<String, String> param) {
        // Create Httpclient object
        CloseableHttpClient httpclient = HttpClients.createDefault();
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // Create uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();
            HttpGet httpGet = new HttpGet(uri);        //Create http GET request
            response = httpclient.execute(httpGet);//Execute request
            // Judge whether the return status is 200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            logger.info("REQUEST GET ExceptionError: [{}]", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                logger.info("REQUEST GET IOExceptionError: [{}]", e.getMessage());
            }
        }
        logger.info("REQUEST GET OK, result={}", resultString);
        return resultString;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    //REQUEST GET
    public static String doPost(String url, Map<String, String> param) {
        // Create Httpclient object
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            HttpPost httpPost = new HttpPost(url); // Create Http Post request
            if (param != null) { // Create parameter list
                List<NameValuePair> paramList = new ArrayList<>();
                logger.info("paramList: {}", param);
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);// Simulation form
            }
            response = httpClient.execute(httpPost);// Execute http request
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");

        } catch (Exception e) {
            logger.info("REQUEST POST ExceptionError: {}", e.getMessage());
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                logger.info("REQUEST POST IOExceptionError: {}", e.getMessage());
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }

    public static String doPostJson(String url, String json) {
        // Create Httpclient object
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            HttpPost httpPost = new HttpPost(url);
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            response = httpClient.execute(httpPost);// Execute http request
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                logger.info("doPostJson IOExceptionError: {}", e.getMessage());
            }
        }
        return resultString;
    }

}

RedisUtils :

/**
 * @author raojinan
 * @version 1.0
 * @date 2020/9/28 12:35
 */
@Component
public class RedisUtils {
    @Autowired
    private StringRedisTemplate redisTemplate;
    private static RedisUtils redisUtils;

    @PostConstruct
    public void init() {
        redisUtils = this;
        redisUtils.redisTemplate = this.redisTemplate;
    }


    /*--------------------------------------key Operation-------------------------------------------*/

    /**
     * Is there a key
     *
     * @param key
     * @return
     */
    public static Boolean hasKey(String key) {
        return redisUtils.redisTemplate.hasKey(key);
    }

    /**
     * Set expiration time
     *
     * @param key
     * @param date
     * @return
     */
    public static Boolean expireAt(String key, Date date) {
        return redisUtils.redisTemplate.expireAt(key, date);
    }

    /**
     * One click set expiration time
     *
     * @param key
     * @param value
     * @param timeout ((in seconds)
     */
    public static void set(String key, String value, long timeout) {
        redisUtils.redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }
    /*--------------------------------------String Operation-------------------------------------------*/

    /**
     * Set the value of the specified key
     *
     * @param key
     * @param value
     */
    public static void set(String key, String value) {

        redisUtils.redisTemplate.opsForValue().set(key, value);
    }

    /**
     * Gets the value of the specified key
     *
     * @param key
     * @return
     */
    public static String get(String key) {

        return redisUtils.redisTemplate.opsForValue().get(key);
    }
    /*--------------------------------------hash Operation-------------------------------------------*/

    /**
     * Gets the value of the specified field stored in the hash table
     *
     * @param key
     * @param field
     * @return
     */
    public static Object hGet(String key, String field) {
        return redisUtils.redisTemplate.opsForHash().get(key, field);
    }

    /**
     * Stores the value of the specified field in the Greek table
     *
     * @param key
     * @param hashKey
     * @param value
     */
    public static void hPut(String key, String hashKey, String value) {
        redisUtils.redisTemplate.opsForHash().put(key, hashKey, value);
    }
    /**
     * Set expiration time for hash key
     *
     * @param key

     */
    public static void setHashKeyTime(String key, long timeout, TimeUnit unit) {
        redisUtils.redisTemplate.expire(key, timeout, unit);
    }

    /**
     * Gets the value of all the given fields
     *
     * @param key
     * @return
     */
    public static Map<Object, Object> hGetAll(String key) {
        return redisUtils.redisTemplate.opsForHash().entries(key);
    }

    /**
     * Check whether the specified field exists in the hash table key
     *
     * @param key
     * @param field
     * @return
     */
    public static boolean hExists(String key, String field) {
        return redisUtils.redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * Gets the number of fields in the hash table
     *
     * @param key
     * @return
     */
    public static Long hSize(String key) {
        return redisUtils.redisTemplate.opsForHash().size(key);
    }


}

2, Some explanations

1. success: function (res){}

res is the content returned by the wechat server after the wx.getUserProfile interface is triggered

login() {
    wx.getUserProfile({
      desc: 'You must authorize it before you can continue to use it',
      success: res => {
        let user = res.userInfo
        // Cache user information locally
        wx.setStorageSync('user', user)
        console.log("User information", user)
        this.setData({
          userInfo: user
        })
      },
      fail: res => {
        console.log('privilege grant failed', res)
      }
    })
  },

reference resources

Data dynamic binding

{{message}}

//js is as follows
Page({
data: {
message: "I am dynamically bound data"
}
})

Posted by barkster on Thu, 23 Sep 2021 05:16:24 -0700