我們創建了支付寶開放平臺的網頁&移動應用,審覈通過後,我們需要拿到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、新浪微博的第三方授權登錄,支付寶需要用到接口加簽的操作,但我們使用支付寶平臺提供的工具也很容易
- 五、總結
如您在閱讀中發現不足,歡迎留言!!!