【第三方互联】十二、支付宝(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 对象,该对象包含了该用户的所有信息,建议观看源代码

扫描二维码关注公众号,回复: 10017324 查看本文章

以上,就是完成 “支付宝” 授权登录的过程,相比起腾讯QQ新浪微博的第三方授权登录,支付宝需要用到接口加签的操作,但我们使用支付宝平台提供的工具也很容易

  • 五、总结
    授权登录总结
    如您在阅读中发现不足,欢迎留言!!!
发布了71 篇原创文章 · 获赞 127 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40065776/article/details/104979271