[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](https://github.com/settings/apps) \[2\] [About creating GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps)

相关推荐
BestAns8 小时前
一文带你吃透 Java 反射机制
java·后端
wasp5208 小时前
AgentScope Java 核心架构深度解析
java·开发语言·人工智能·架构·agentscope
2501_916766548 小时前
【Springboot】数据层开发-数据源自动管理
java·spring boot·后端
自在极意功。8 小时前
MyBatis 动态 SQL 详解:从基础到进阶实战
java·数据库·mybatis·动态sql
软件管理系统8 小时前
基于Spring Boot的便民维修管理系统
java·spring boot·后端
百***78759 小时前
Step-Audio-2 轻量化接入全流程详解
android·java·gpt·php·llama
快乐肚皮9 小时前
MySQL递归CTE
java·数据库·mysql·递归表达式
廋到被风吹走9 小时前
【Spring】DispatcherServlet解析
java·后端·spring
廋到被风吹走9 小时前
【Spring】PlatformTransactionManager详解
java·spring·wpf