【第三方互聯】十二、支付寶(Alipay)授權第三方登錄

我們創建了支付寶開放平臺的網頁&移動應用,審覈通過後,我們需要拿到appid,支付寶公鑰,私鑰進項開發

  • 一、添加應用信息至項目環境中
    配置信息
    我們保存了 appid、應用私鑰、支付寶公鑰、支付寶回調地址等信息,這裏的公鑰爲支付寶開放平臺爲我們生成的“支付寶公鑰

  • 二、引入 Maven 依賴

<!-- 支付寶SDK -->
<dependency>
	<groupId>com.alipay.sdk</groupId>
	<artifactId>alipay-sdk-java</artifactId>
	<version>4.9.28.ALL</version>
</dependency>
<!-- alibaba的fastjson -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.51</version>
</dependency>

其餘依賴請自行添加

  • 三、在頁面放置 “支付寶” 授權登錄的 DOM 元素
<a th:href="@{alipay/auth}" class="link" title="支付寶登錄"><i class="iconfont icon-zhifubao"></i></a>

這裏使用的是阿里的 iconfont 圖標

  • 四、創建 “支付寶” 授權登錄的 Controller,AlipayController.java

1、從配置文件中獲取 “支付寶” 配置信息

/**
 * 微博授權中提供的 appid 和 appkey
 */
@Value("${alipay.oauth.appid}")
public String APPID;
@Value("${alipay.oauth.callback-url}")
public String CALL_BACK_URL;
@Value("${alipay.oauth.private-key}")
public String PRIVATE_KEY;
@Value("${alipay.oauth.public-key}")
public String PUBLIC_KEY;

2、登錄按鈕點擊後的接口

/**
 * 請求授權頁面
 */
@GetMapping(value = "/auth")
public String qqAuth(HttpSession session) {
    // 用於第三方應用防止CSRF攻擊
    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    session.setAttribute("state", uuid);

    // Step1:獲取Authorization Code
    String url = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?scope=auth_user" +
            "&app_id=" + APPID +
            "&redirect_uri=" + URLEncoder.encode(CALL_BACK_URL) +
            "&state=" + uuid;

    return PasswordUtils.redirectTo(url);
}

接口文檔中建議我們在授權登錄時傳入一個加密的數據防止被攻擊,我們傳入了UUID,最後重定向到授權頁面
授權界面
3、當該用戶點擊“授權”按鈕,同意授權後,就會回調到我們在應用中填寫的回調地址裏去

/**
 * 授權回調
 */
@GetMapping(value = "/callback")
public String qqCallback(HttpServletRequest request) throws Exception {
    // 獲取session
    HttpSession session = request.getSession();
    // 得到auth_code
    String authCode = request.getParameter("auth_code");
    // 我們放在地址中的狀態碼
    String state = request.getParameter("state");
    String uuid = (String) session.getAttribute("state");
    // 驗證信息我們發送的狀態碼
    if (null != uuid) {
        // 狀態碼不正確,直接返回登錄頁面
        if (!uuid.equals(state)) {
            return PasswordUtils.redirectTo("/login");
        }
    }

    // Step2:通過auth_code獲取Access Token 以及 user_id
    JSONObject tokenJson = AlipayHttpClient.getAccessToken(APPID, PRIVATE_KEY, PUBLIC_KEY, authCode);
    // Step3:通過auth_code獲取用戶信息
    JSONObject userJson = AlipayHttpClient.getUserInfo(APPID, PRIVATE_KEY, PUBLIC_KEY, tokenJson.getString("accessToken"));
    // 如果請求用戶信息失敗,則返回到登錄界面
    if ("0".equals(userJson.getString("code"))) {
        return PasswordUtils.redirectTo("/login");
    }
    // 根據user_id在數據庫中查找是否存在此用戶
    UserInfo userInfo = userInfoService.getUserInfo(tokenJson.getString("userId"), Const.UserCategory.USER_CATEGORY_ALIPAY);
    // 如果存在此用戶,則檢查該用戶是否合法,返回首頁
    if (null != userInfo) {
        // 該用戶被凍結
        if (2 == userInfo.getStatus()) {
            return PasswordUtils.redirectTo("/login");
        }
        // 登錄成功
        else {
            session.setAttribute(Const.SYSTEM_USER_SESSION, userInfo);
            // 新增一條登錄日誌
            loginLogService.saveLoginLog(userInfo.getId(), ServletUtils.getServletPojo(request));
        }
    }
    // 系統中不存在該用戶,則需要新建一個用戶保存到數據庫中,並登錄
    else {
        // 拿到我們獲取到的用戶信息
        AlipayUserInfoShareResponse alipayUser = (AlipayUserInfoShareResponse) userJson.get("user");
        // 隨機生成賬戶
        String loginAccount = Const.Number.NUMBER_ONE + RandomUtils.getCurrentTimeMillis(Const.Number.NUMBER_EIGHT);
        // 隨機生成鹽值
        String salt = PasswordUtils.getSalt();
        // 加密後的密碼,默認密碼123456
        String password = PasswordUtils.getMd5("123456", loginAccount, salt);
        // 性別
        String sexStr = alipayUser.getGender();
        int sex = Const.Sex.SEX_SECRECY;
        // 男
        if ("M".equalsIgnoreCase(sexStr)) {
            sex = Const.Sex.SEX_MAN;
        }
        // 女
        else if ("F".equalsIgnoreCase(sexStr)) {
            sex = Const.Sex.SEX_WOMAN;
        }
        // 保存新用戶
        userInfoService.saveUserInfo(loginAccount, alipayUser.getNickName(), alipayUser.getUserName(), "", password, salt, alipayUser.getAvatar(), sex, tokenJson.getString("userId"), Const.UserCategory.USER_CATEGORY_ALIPAY, StringUtils.isEmpty(alipayUser.getMobile()) ? alipayUser.getMobile() : alipayUser.getPhone());
        // 根據openid在數據庫中查找是否存在此用戶
        userInfo = userInfoService.getUserInfo(tokenJson.getString("userId"), Const.UserCategory.USER_CATEGORY_ALIPAY);
        // 將當前用戶保存到session中去
        session.setAttribute(Const.SYSTEM_USER_SESSION, userInfo);
        // 默認加主號爲好友
        friendInfoDao.saveFridendInfo(Const.Number.NUMBER_ONE, userInfo.getId());
        // 新增一條登錄日誌
        loginLogService.saveLoginLog(userInfo.getId(), ServletUtils.getServletPojo(request));
    }
    return PasswordUtils.redirectTo("/success");
}

以上代碼,從我自己的項目中拷貝而來,如果你直接使用,你需要對其業務代碼進行修改

4、第2步代碼中所用到的網絡接口方法,我放在了 AlipayHttpClient.java 文件中,主要有兩個方法

/**
 * auth_code換取access_token與user_id
 *
 * @param appid
 * @param privateKey 私鑰
 * @param publicKey  公鑰
 * @param authCode   授權碼
 * @return
 * @throws AlipayApiException
 */
public static JSONObject getAccessToken(String appid, String privateKey, String publicKey, String authCode) throws AlipayApiException {
    // 返回對象
    JSONObject res = new JSONObject();
    /**
     * 支付寶網關(固定)
     * APPID 即創建應用後生成
     * 開發者私鑰,由開發者自己生成
     * 參數返回格式,只支持json
     * 編碼集,支持GBK/UTF-8
     * 支付寶公鑰,由支付寶生成
     * 商戶生成簽名字符串所使用的簽名算法類型,目前支持RSA2和RSA,推薦使用RSA2
     */
    AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appid, privateKey, "json", "UTF-8", publicKey, "RSA2");
    // 請求對象
    AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
    // 第一步獲取到的:auth_code
    request.setCode(authCode);
    // 授權類型
    request.setGrantType("authorization_code");
    // 發起請求
    AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(request);
    // 拿到 access_token
    res.put("accessToken", oauthTokenResponse.getAccessToken());
    // 拿到 user_id
    res.put("userId", oauthTokenResponse.getUserId());
    return res;
}

/**
 * 使用 access_token 獲取用戶信息
 *
 * @param appid
 * @param privateKey  私鑰
 * @param publicKey   公鑰
 * @param accessToken 令牌
 * @throws AlipayApiException
 */
public static JSONObject getUserInfo(String appid, String privateKey, String publicKey, String accessToken) throws AlipayApiException {
    // 返回對象
    JSONObject res = new JSONObject();
    /**
     * 支付寶網關(固定)
     * APPID 即創建應用後生成
     * 開發者私鑰,由開發者自己生成
     * 參數返回格式,只支持json
     * 編碼集,支持GBK/UTF-8
     * 支付寶公鑰,由支付寶生成
     */
    AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appid, privateKey, "json", "UTF-8", publicKey, "RSA2");
    // 請求對象
    AlipayUserInfoShareRequest request = new AlipayUserInfoShareRequest();
    // 傳入token,發起請求
    AlipayUserInfoShareResponse response = alipayClient.execute(request, accessToken);
    // 請求成功
    if ("10000".equals(response.getCode())) {
        res.put("code", 1);
        res.put("user", response);
    }
    // 請求失敗
    else {
        res.put("code", 0);
        res.put("msg", "獲取用戶信息失敗");
    }
    return res;
}

最終我們獲取到用戶的信息是一個 AlipayUserInfoShareResponse 對象,該對象包含了該用戶的所有信息,建議觀看源代碼

以上,就是完成 “支付寶” 授權登錄的過程,相比起騰訊QQ新浪微博的第三方授權登錄,支付寶需要用到接口加簽的操作,但我們使用支付寶平臺提供的工具也很容易

  • 五、總結
    授權登錄總結
    如您在閱讀中發現不足,歡迎留言!!!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章