[SpringStack] 快速登录-9分钟给你站点接入Github登录

本文章案例为Java在web端接入GitHub登录,大致流程相同。

一: 设置Github的ClientId和

1.1 创建一个newOAuth app

1.2 创建成功之后会生成一个Clinet ID和 Client secrets 用于在服务端交互时候使用

二:客户端按钮跳转代码

按钮的跳转地址为:

https://github.com/login/oauth/authorize?client_id=KaTeX parse error: Expected 'EOF', got '&' at position 16: {你生成的client_id}&̲redirect_uri={你服务端的跳转地址}.

假如我的client_id为 Ov22342345234,服务端的回调地址:http://127.0.0.1:8080/admin/github/callback
则我客户端的地址为:https://github.com/login/oauth/authorize?client_id=Ov22342345234\&redirect_uri=http://127.0.0.1:8080/admin/github/callback

然后嵌入到web页面中。

html 复制代码
<div class="row">
    <div class="col-xs-12">
       <a href="https://github.com/login/oauth/authorize?client_id=${你生成的client_id}&redirect_uri=http://127.0.0.1:8080/admin/github/callback" class="btn btn-default btn-block btn-flat">
          使用 GitHub 登录
       </a>
    </div>
</div>

三:服务端回调地址:

用户在客户端点击GitHub登录点击授权登录,GitHub会回调到redirect_uri的地址,在后面会带一个code码,我们服务端回拿着这个code码换取access_token,因为要校验client_id下服务的唯一性

3.1 表设计:

如果B2C业务模式的话:C端用户player,B端用户 user

如果B2B2C业务模式的话: C端用户player,B端用户 user,多一个M端用户manager(用来控制平台的运转比如数据修复等等相关业务)

more字段是存储三方回调成功之后的用户信息,比如:{"login":"xxx","id":xxx,"avatar_url":"xxx","name":"xxx","email":"xxxx@email.com"}

sql 复制代码
CREATE TABLE `third_user_account` (
  `third_user_account_id` bigint(20) unsigned NOT NULL COMMENT '主键ID',
  `create_id` bigint(20) NOT NULL COMMENT '创建人 @link user.id (-1为:系统)',
  `create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
  `modifier_id` bigint(20) unsigned DEFAULT NULL COMMENT '修改人id @link user.id (-1为:系统)',
  `modify_time` datetime(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '修改时间',
  `version` int(11) NOT NULL DEFAULT '1' COMMENT '版本号',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除: true 删除 false 未删除',
  `enabled` tinyint(1) DEFAULT '1' COMMENT '启用状态: true 启用 (默认)  false: 禁用',
  `is_bound` tinyint(1) DEFAULT '0' COMMENT '是否已绑定: 0 未绑定(默认) 1 已绑定 ',
  `third_plat_type_code` enum('github','qq','wechat') NOT NULL COMMENT '三方平台类型',
  `third_unique` varchar(100) NOT NULL COMMENT '三方平台唯一标识(如三方ID标识)',
  `third_username` varchar(155) DEFAULT NULL COMMENT '账号',
  `third_email` varchar(155) DEFAULT NULL COMMENT '邮箱',
  `more` text DEFAULT NULL COMMENT '其他',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`third_user_account_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='三方用户账号表';

四: 编写服务端代码 (本文以Java为例)

这里的代码是GitHub

java 复制代码
@RequestMapping("/github/callback")
public String handleGitHubCallback(@RequestParam("code") String code, HttpServletResponse response) {
    String accessToken = getAccessTokenFromGitHub(code);
    // 使用 access_token 获取用户信息
    GitHubUser user = getGitHubUserInfo(accessToken);
    // 绑定用户
    XxlJobUser jobUser = bindGitHubUserToPlatform(user);
    if (!validUserLogin(jobUser)) {
        log.error("用户:{}, 账号不存在或已经禁用", jobUser);
        return "账号不存在或已经禁用";
    }
    log.info("callback code:{}, state:{}", jobUser);
    CookieUtil.set(response, LOGIN_IDENTITY_KEY, makeToken(jobUser), Boolean.TRUE);
    // 重定向到用户登录后的页面
    return "redirect:/";
}
  • 使用 OkHttp 获取 GitHub access_token
java 复制代码
private String getAccessTokenFromGitHub(String code) {
    String clientId = "你生成的client_id";
    String clientSecret = "你的密钥";
    String url = "https://github.com/login/oauth/access_token";
    String redirectUri = "http://127.0.0.1:8080/admin/github/callback";

    OkHttpClient client = new OkHttpClient();
    // 构建请求体
    RequestBody formBody = new FormBody.Builder()
            .add("client_id", clientId)
            .add("client_secret", clientSecret)
            .add("code", code)
            .add("redirect_uri", redirectUri)
            .build();

    // 创建 POST 请求
    Request request = new Request.Builder()
            .url(url)
            .post(formBody)
            .header("Accept", "application/json")
            .build();

    try (Response response = client.newCall(request).execute()) {
        if (!response.isSuccessful()) {
            throw new IOException("Unexpected code " + response);
        }
        // 获取响应体并返回 access_token
        String responseBody = response.body().string();
        return parseAccessTokenWithGson(responseBody);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
  • 使用 Gson 解析 access_token
java 复制代码
private String parseAccessTokenWithGson(String responseBody) {
    // 使用 Gson 解析返回的 JSON 响应
    JsonObject jsonObject = JsonParser.parseString(responseBody).getAsJsonObject();
    return jsonObject.get("access_token").getAsString();
}
  • 根据 GitHub 用户信息绑定或创建用户账户.检查用户 email 是否已经注册,或者根据 GitHub id 进行绑定.
java 复制代码
/**
 * 根据 GitHub 用户信息绑定或创建用户账户.
 * 检查用户 email 是否已经注册,或者根据 GitHub id 进行绑定.
 * @param gitHubUser
 * @return
*/
public XxlJobUser bindGitHubUserToPlatform(GitHubUser gitHubUser) {
    List<ThirdUserAccountPO> list = ChainWrappers.lambdaQueryChain(thirdUserAccountDAO).eq(ThirdUserAccountPO::getThirdUnique, gitHubUser.getId())
            .eq(ThirdUserAccountPO::getThirdPlatTypeCode, ThirdPlatformTypeEnum.GITHUB.getCode()).list();
    ThirdUserAccountPO thirdUserAccountPO;
    if (CollectionUtils.isEmpty(list)) {
        thirdUserAccountPO = new ThirdUserAccountPO();
        thirdUserAccountPO.setThirdUnique(String.valueOf(gitHubUser.getId()));
        thirdUserAccountPO.setCreateId(-1L);
        thirdUserAccountPO.setThirdPlatTypeCode(ThirdPlatformTypeEnum.GITHUB.getCode());
        Optional.ofNullable(gitHubUser.getEmail()).ifPresent(v -> thirdUserAccountPO.setThirdEmail(v));
        Optional.ofNullable(gitHubUser.getLogin()).ifPresent(v -> thirdUserAccountPO.setThirdUsername(v));
        thirdUserAccountPO.setMore(new Gson().toJson(gitHubUser));
        thirdUserAccountPO.setIsBound(Boolean.TRUE);
        thirdUserAccountDAO.insert(thirdUserAccountPO);
    } else {
        thirdUserAccountPO = list.get(0);
    }

    //生成绑定到后台账户
    XxlJobUser xxlJobUser = ChainWrappers.lambdaQueryChain(xxlJobUserDao)
            .eq(XxlJobUser::getThirdUserAccountId, thirdUserAccountPO.getThirdUserAccountId()).one();

    String thirdUnique = thirdUserAccountPO.getThirdUnique();
    if (xxlJobUser == null) {
        xxlJobUser = new XxlJobUser();
        xxlJobUser.setUsername("gh_".concat(thirdUnique.substring(0,3))
                .concat(thirdUserAccountPO.getThirdUsername()));
        HashCode hashPwd = Hashing.hmacMd5(thirdUnique.getBytes(StandardCharsets.UTF_8)).hashString(thirdUnique, StandardCharsets.UTF_8);
        xxlJobUser.setPassword(hashPwd.toString());
        xxlJobUser.setRole(0);
        xxlJobUser.setThirdUserAccountId(thirdUserAccountPO.getThirdUserAccountId());
        xxlJobUserDao.save(xxlJobUser);
    }
    return xxlJobUser;
}
  • 校验用户是否是可用状态
java 复制代码
private Boolean validUserLogin(XxlJobUser xxlJobUser) {
    if (xxlJobUser.getDeleted() || xxlJobUser.getStatus() != AccountStatusEnum.ENABLED.getCode()) {
        return Boolean.FALSE;
    }
    return Boolean.TRUE;
}

总结

本文只是使用web演示了GitHub的登录接入,如果使用App跳转,只需要把接口请求成功后,返回跳转地址的标识改为跳转回APP就可以了。

参考资料 & 致谢

[1] GitHub Apps

[2] About creating GitHub Apps

相关推荐
SONGW20184 分钟前
其他节点使用kubectl访问集群,kubeconfig配置文件 详解
java·开发语言
许苑向上16 分钟前
最详细【Elasticsearch】Elasticsearch Java API + Spring Boot集成 实战入门(基础篇)
java·数据库·spring boot·elasticsearch
柳叶寒21 分钟前
医院信息化与智能化系统(17)
java·nacos·gateway·全栈·项目
首席架构师专栏22 分钟前
吊打面试官系列:final、finally、finalize 有什么区别?
java
hxj..33 分钟前
【算法】动态规划
java·算法·动态规划
哎呦没40 分钟前
Spring Boot技术实现的导师双选系统架构
spring boot
世间万物皆对象1 小时前
Java 基础教学:高级特性与实战-集合框架
java·开发语言
不爱吃米饭_1 小时前
如何优雅处理异常?处理异常的原则
java·开发语言·spring boot
李少兄1 小时前
IntelliJ IDEA 中创建目录时 `.` 和 `/` 的区别
java·ide·intellij-idea
V+zmm101341 小时前
社区养老服务小程序ssm+论文源码调试讲解
java·服务器·前端·javascript·小程序·毕业设计·1024程序员节