Springboot integrated nail scanning code login

Time:2022-5-4

In the recent project, we need to make a login page with the function of nail scanning code login. Let’s take notes and experience here

The front-end login page code is Vue:
The first step is to index. In the global public HTML add the required JS file

Springboot integrated nail scanning code login

image.png
<script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>

The second step is to modify the previous login page to the following, and adjust the style to your favorite. The login page here is login Vue, the callback address here is consistent with the callback address in your application

Springboot integrated nail scanning code login

image.png
<template>
  <div>
    <el-form ref="loginForm" :model="loginForm">
      <h3>Login</h3>
      <div></div>
    </el-form>
    <!--   Bottom -- >
    <div>
      <span>Login page</span>
    </div>
  </div>
</template>

<script>
import { loginCode } from "@/api/login";
export default {
  name: "Login",
  data() {
    return {
   
    };
  },
  watch: {
    $route: {
      handler: function (route) {
        this.redirect = route.query && route.query.redirect;
      },
      immediate: true,
    },
  },
  mounted() {
    let str = this.$route.query.redirect;
    if (str) {
      let index = str.indexOf("=");
      let code = str.substr(index + 1, str.length);
      this.handleCodeLogin(code);
    } else {
      this.ddLoginInit();
    }
  },
  methods: {
    //Nail scanning code login initialization function
    ddLoginInit() {
      console.log(200);
      let url = encodeURIComponent(` http://localhost:80 `); // Write the pin callback address here
      let appid = ""; // Fill in your appid on the nailing developer platform
      let goto = encodeURIComponent(
        `https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=${appid}&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=${url}`
      );

      let obj = DDLogin({
        ID: "login_container", // corresponds to the div box id just now
        goto: goto,
        style: "border:none;background-color:#FFFFFF;",
        width: 365,
        height: 350,
      });
      let handleMessage = (event) => {
        let origin = event.origin;
        if (origin == "https://login.dingtalk.com") {
          let loginTmpCode = event.data;
          window.location.href = `https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=${appid}&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=${url}&loginTmpCode=${loginTmpCode}`;
        }
      };
      if (typeof window.addEventListener != "undefined") {
        window.addEventListener("message", handleMessage, false);
      } else if (typeof window.attachEvent != "undefined") {
        window.attachEvent("onmessage", handleMessage);
      }
    },

    //Nailing login function
    async handleCodeLogin(code) {
      //Use code here according to your needs
      let res = await loginCode(code);
      if (res) {
        //Perform permission verification according to the required user information returned
      }
    },

Step 3: login JS, write the request method required in your login function

//Nail scanning login interface
export function loginCode(code) {
  return request({
    url: '/DingLogin?code='+code,
    method: 'get',
  })
}

This is the end of the front-end. The next step is the back-end code. I use springboot for the back-end here

The first step is to add SDK in the POM file, add it in the main POM file, and then reference it where necessary. I’m adding it in the gateway service and the main POM

Springboot integrated nail scanning code login

image.png
//This is the main POM XML added
<dingtalk.version>1.0.1</dingtalk.version>
<dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>alibaba-dingtalk-service-sdk</artifactId>
                <version>${dingtalk.version}</version>
            </dependency>
//This is POM in auth Added in XNL
 <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>alibaba-dingtalk-service-sdk</artifactId>
        </dependency>

The second step is to create a login controller and copy the code in the nailing tutorial document
Nailing third-party code scanning login document address:https://developers.dingtalk.com/document/tutorial/scan-qr-code-to-log-on-to-third-party-websites?spm=ding_open_doc.21783679.J_8506627640.1.3db24ce9awRO4R
Then an error is reported. There are two methods that can’t be found. The jar package here may have been updated and the document hasn’t been updated. I directly give the modified code to me

package com.dualshare.auth.controller;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiSnsGetuserinfoBycodeRequest;
import com.dingtalk.api.request.OapiUserGetUseridByUnionidRequest;
import com.dingtalk.api.request.OapiV2UserGetRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
import com.dingtalk.api.response.OapiUserGetUseridByUnionidResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.dualshare.auth.service.SysLoginService;
import com.dualshare.common.core.domain.R;
import com.dualshare.common.security.service.TokenService;
import com.dualshare.system.api.model.LoginUser;
import com.taobao.api.ApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.Map;

/**
 *Nail scanning code login
 */
@RestController
public class LoginController {

    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysLoginService sysLoginService;


    @Value("${Ding.appId}")
    private String appId;

    @Value("${Ding.appSecret}")
    private String appSecret;

    @Value("${Ding.getTokenUrl}")
    private String getTokenUrl;

    @Value("${Ding.getUserInfoUrl}")
    private String getUserInfoUrl;

    @Value("${Ding.getUnionIdUrl}")
    private String getUnionIdUrl;

    @Value("${Ding.getUserByUserIdUrl}")
    private String getUserByUserIdUrl;

    @RequestMapping(value = "/DingLogin")
    public R<?> DingLogin(@RequestParam("code") String code) {
        try {
            //Get access_ Token. Note that the formal code should have exception flow processing
            String access_token = getToken();
            //Obtain the personal information of the authorized user through the temporary authorization code
            DefaultDingTalkClient client2 = new DefaultDingTalkClient(getUserInfoUrl);
            OapiSnsGetuserinfoBycodeRequest reqBycodeRequest = new OapiSnsGetuserinfoBycodeRequest();
            //Scan the QR code and jump to the specified redirect_ The temporary authorization code appended to the URL after the URI
            reqBycodeRequest.setTmpAuthCode(code);
            //Modify appid and appsecret to the appid and appsecret created during code scanning login in step 3
            OapiSnsGetuserinfoBycodeResponse bycodeResponse = client2.execute(reqBycodeRequest, appId, appSecret);
            //Get userid according to unionid
            String unionid = bycodeResponse.getUserInfo().getUnionid();
            DingTalkClient clientDingTalkClient = new DefaultDingTalkClient(getUnionIdUrl);
            OapiUserGetUseridByUnionidRequest reqGetbyunionidRequest = new OapiUserGetUseridByUnionidRequest();
            reqGetbyunionidRequest.setUnionid(unionid);
            OapiUserGetUseridByUnionidResponse oapiUserGetbyunionidResponse = clientDingTalkClient.execute(reqGetbyunionidRequest, access_token);
            if (oapiUserGetbyunionidResponse.getErrcode() == 60121L) {
                return R.fail();
            }
            //Get user information according to userid
            String rBody = oapiUserGetbyunionidResponse.getBody();
            String userid=null;
            if (rBody!=null){
                if (JSONObject.parseObject(rBody).get("result")!=null){
                    Map map =JSONObject.parseObject(JSONObject.parseObject(rBody).get("result").toString());
                    if (map.get("userid")!=null){
                        userid =map.get("userid").toString();
                    }
                }
            }
            if (userid==null){
                System.out.println(oapiUserGetbyunionidResponse.getErrmsg());
                return R.fail(oapiUserGetbyunionidResponse.getErrmsg());
            }
            DingTalkClient clientDingTalkClient2 = new DefaultDingTalkClient(getUserByUserIdUrl);
            OapiV2UserGetRequest reqGetRequest = new OapiV2UserGetRequest();
            reqGetRequest.setUserid(userid);
            reqGetRequest.setLang("zh_CN");
            OapiV2UserGetResponse rspGetResponse = clientDingTalkClient2.execute(reqGetRequest, access_token);
            System.out.println(rspGetResponse.getBody());
            String body = rspGetResponse.getBody();
            Map map =JSONObject.parseObject(JSONObject.parseObject(body).get("result").toString());
            //According to their own needs, get the corresponding required things and return them to the front end
            return R.ok();
        } catch (ApiException e) {
            e.printStackTrace();
            return R.fail(e);
        }
    }

    public String getToken() {
        try {
            DefaultDingTalkClient client = new DefaultDingTalkClient(getTokenUrl);
            OapiGettokenRequest request = new OapiGettokenRequest();
            //Fill in the appkey of the application created in step 1
            request.setAppkey(appId);
            //Fill in the appsecret of the application created in step 1
            request.setAppsecret(appSecret);
            request.setHttpMethod("GET");
            OapiGettokenResponse response = client.execute(request);
            String accessToken = response.getAccessToken();
            return accessToken;
        } catch (ApiException e) {
            throw new RuntimeException();
        }
    }
}

Configuration in YML

#Dingding code scanning configuration
Ding:
  Appid: "your appkey"
  Appsecret: "your appsecret"
  getTokenUrl: "https://oapi.dingtalk.com/gettoken"
  getUserInfoUrl: "https://oapi.dingtalk.com/sns/getuserinfo_bycode"
  getUnionIdUrl: "https://oapi.dingtalk.com/topapi/user/getbyunionid"
  getUserByUserIdUrl: "https://oapi.dingtalk.com/topapi/v2/user/get"

Here, start the front and back end, and then visit the login page

Springboot integrated nail scanning code login

image.png