Spring Boot实现Oauth2认证授权登录Github

OAuth2 原理介绍

OAuth2 是一种授权框架,允许第三方应用获取有限的资源访问权限,而无需暴露用户的密码。

核心角色

  • Resource Owner(资源所有者):用户
  • Client(客户端):第三方应用
  • Authorization Server(授权服务器):负责认证和授权
  • Resource Server(资源服务器):存储受保护资源

四种授权模式

  1. 授权码模式(最安全,适合服务端应用)
  2. 密码模式(用户直接提供密码给客户端)
  3. 客户端凭证模式(客户端以自己的名义访问)
  4. 隐式模式(已废弃,不推荐)

工作流程总结

  1. 用户访问客户端应用
  2. 客户端重定向用户到授权服务器
  3. 用户在授权服务器登录并授权
  4. 授权服务器返回授权码给客户端
  5. 客户端使用授权码向授权服务器请求令牌
  6. 授权服务器验证授权码,返回访问令牌
  7. 客户端使用访问令牌访问资源服务器上的受保护资源

实际调用流程

sequenceDiagram participant User as 用户 participant Front as 前端 participant Auth as AuthService participant Provider as GitHub/Google OAuth participant DB as 数据库 User->>Front: 点击 "GitHub 登录" 按钮 Note over Front: 生成/读取 device_id<br/>拼接到 URL Front->>Front: window.location.href =<br/>"auth.dengwei.site/api/auth/oauth/github?device_id=xxx" Note over Front: 页面跳离,进入 OAuth 流程 Front->>Auth: GET /api/auth/oauth/github?device_id=xxx Auth->>Auth: 生成 state_device_id (防CSRF + 设备标识,device_id可选) Auth-->>User: 302 重定向到 GitHub 授权页 User->>Provider: 在 GitHub 上授权 Provider-->>Auth: 302 到 callback<br/>GET /oauth/github/callback?code=xxx&state=uuid|device_id Auth->>Auth: 从 state 提取 device_id Auth->>Provider: 用 code 换 access_token Provider-->>Auth: access_token + 用户信息 Auth->>DB: 查询 user_oauth_bindings<br/>(provider + provider_user_id) alt 已有绑定记录 DB-->>Auth: 关联的 user_id else 首次登录,自动创建 Auth->>DB: INSERT users Auth->>DB: INSERT user_oauth_bindings end Auth->>DB: 删除该设备旧 refresh_token<br/>DELETE WHERE user_id + client_id Auth->>Auth: 签发 JWT (access + refresh) Auth->>DB: 存储新 refresh_token_hash + client_id Note over Auth: 设置 HttpOnly Cookie:<br/>Set-Cookie: access_token=...<br/>Set-Cookie: refresh_token=... Auth-->>Front: 302 → test.dengwei.site/oauth/callback Note over Front: 页面跳转回前端<br/>URL 中无 token (全在 cookie 里) Front->>Front: 组件挂载 → 立即 Navigate("/") Front->>Auth: GET /api/auth/me (cookie 自动附带) Auth-->>Front: { id, email, display_name, avatar_url } Front->>Front: AuthContext.dispatch<br/>{ type: 'LOGIN_SUCCESS' } Front-->>User: 已登录,显示首页 ✅

说明:

  1. 查询到用户信息后的处理逻辑自己可以根据需要修改,如是否替换原有头像等
  2. 签发新的access_token和refresh_token后,返回给前端的方式有多种,可以使用URL的hash拼接。
  3. 是否需要区分设备client_id看自己需要

接口

  1. /api/auth/oauth/github 启动授权流程,这里由后端触发,前端处理也可以。用于拼接URL,重定向到Github授权页面,回调地址写下面的callback地址。

  2. /api/auth/oauth/github/callback接收Github的回调,包含授权码,通过授权码再去获取access_token -> 通过access_token查询用户信息 -> 自定义处理用户信息 -> 生成自己服务的access_token和refresh_token返回给前端

本地测试方法

我是用的是Cloudflare的tunnels,安装好服务后,将本地的前端和后端绑定到两个域名上,进行测试的。

Github需要在Settings/Developer Settings/OAuth Apps 下添加一个client。

	// 重定向地址
    @Override
    public String getAuthorizeUrl(String redirectUri, String state) {
        return UriComponentsBuilder.fromHttpUrl("https://github.com/login/oauth/authorize")
            .queryParam("client_id", clientId)
            .queryParam("redirect_uri", redirectUri)
            .queryParam("state", state)
            .queryParam("scope", "read:user,user:email")
            .build()
            .toUriString();
    }

    @Override
    protected String getUserInfoUrl() {
        return "https://api.github.com/user";
    }

    @Override
    protected String getTokenUrl() {
        // 通过code换取access_token
        return "https://github.com/login/oauth/access_token";
    }

    protected MultiValueMap<String, String> buildTokenRequestBody(String code, String redirectUri) {
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("client_id", clientId);
        body.add("client_secret", clientSecret);
        body.add("code", code);
        body.add("redirect_uri", redirectUri);
        return body;
    }

登录演示


原文链接:https://blog.dengwei.site/article/spring-boot-oauth2-github-login

posted @ 2026-06-02 15:13  衣来伸手饭来张口  阅读(17)  评论(0)    收藏  举报