Github OAuth 第三方登录示例

1、第三方登录原理

第三方登录的原理是借助OAuth授权来实现,首先用户先向客户端提供第三方网站的数据证明自己的身份获取授权码,然后客户端拿着授权码与授权服务器建立连接获得一个Access Token,之后客户端就可以通过Access Token来与资源服务器进行交互。

使用OAuth的好处是提供给用户一个特定的密钥,用户持有这个密钥可以访问应用中的任何信息,而不需要向网站提供用户名&密码,可以实现跨系统共享用户授权协议。

通过控制用户持有的密钥,可以很方便的控制用户可以访问的资源,以及控制密钥的过期时间。

以下是来自维基百科对于OAuth的介绍

交互流程如下:

Spring Boot整合OAuth2实现GitHub第三方登录-LMLPHP

2、GitHub实现第三方登录

首先需要在github中对应用进行登记,让Github知道谁在发送请求。

访问这个网址,填写登记表

Spring Boot整合OAuth2实现GitHub第三方登录-LMLPHP

提交成功之后,GitHub会返回Client ID & Client Secrets ,这是应用的身份识别码

Spring Boot整合OAuth2实现GitHub第三方登录-LMLPHP

创建一个SpringBoot工程,pom.xml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.17</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.pp</groupId>
    <artifactId>springboot-oauth2-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-oauth2-api</name>
    <description>springboot整合oauth2,实现GitHub第三方登录</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

将ID和密钥添加到配置文件application.yml中:

# 项目端口号
server:
  port: 8080
#  GitHub认证相关参数
github:
    client:
      id: xxx
      secret: xxx

创建一个实体类,用于映射授权成功产生的Token令牌:

import com.fasterxml.jackson.annotation.JsonProperty;
/**
 *
 * Token令牌 - 响应参数
 *
 * @author supanpan
 * @date 2023/10/25
 */
public class AccessTokenResponse {

    @JsonProperty("access_token")
    private String accessToken;

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }
}

OAuthController如下:

**
 * @author supanpan
 * @date 2023/10/25
 */
@Controller
public class OAuthController {

    @Value("${github.client.id}")
    private String clientId;

    @Value("${github.client.secret}")
    private String clientSecret;

    @GetMapping("/oauth/redirect")
    public String handleRedirect(@RequestParam("code") String requestToken, Model model) {
        // 使用RestTemplate来发送HTTP请求
        RestTemplate restTemplate = new RestTemplate();

        // 获取Token的Url
        String tokenUrl = "https://github.com/login/oauth/access_token" +
                "?client_id=" + clientId +
                "&client_secret=" + clientSecret +
                "&code=" + requestToken;

        // 使用restTemplate向GitHub发送请求,获取Token
        AccessTokenResponse tokenResponse = restTemplate.postForObject(tokenUrl, null, AccessTokenResponse.class);

        // 从响应体中获取Token数据
        String accessToken = tokenResponse.getAccessToken();

        // 携带Token向GitHub发送请求
        String apiUrl = "https://api.github.com/user";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "token " + accessToken);
        HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, entity, String.class);
        model.addAttribute("userData", response.getBody());

        return "welcome";
    }
}

SpringBoot启动器

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootOauth2ApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootOauth2ApiApplication.class, args);
    }

}

还需要编写两个html页面,index.html和welcome.html

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>OAuth2 Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
<a id="login">Login with GitHub</a>

<script>
    const client_id = 'xxxx';

    const authorize_uri = 'https://github.com/login/oauth/authorize';
    const redirect_uri = 'http://localhost:8080/oauth/redirect';

    const link = document.getElementById('login');
    link.href = `${authorize_uri}?client_id=${client_id}&redirect_uri=${redirect_uri}`;
</script>

</body>

</html>

welcome.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hello</title>
</head>

<body>
    <h1>Welcome</h1>
    <div th:text="${userData}"></div>
</body>

</html>

启动项目,浏览器访问localhost:8080,会跳转到index页面,点击链接会跳转到GitHub应用授权页面

点击跳转到GitHub授权之后,GitHub会询问示例代码正在请求数据,您是否同意授权。

Spring Boot整合OAuth2实现GitHub第三方登录-LMLPHP

用户同意授权, GitHub 就会跳转到redirect_uri指定的跳转网址,并且带上授权码,跳转回来的 URL 就是下面的样子

// code参数就是授权码
http://localhost:8080/oauth/redirect?code:4ea423f2ec1e04c6376a

如下是服务的响应数据:

access token: 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
{
  login: 'AtwoodPa',
  id: 110728122,
  node_id: 'U_kgDOBpmTug',
  avatar_url: 'https://avatars.githubusercontent.com/u/110728122?v=4',
  gravatar_id: '',
  url: 'https://api.github.com/users/AtwoodPa',
  html_url: 'https://github.com/AtwoodPa',
  followers_url: 'https://api.github.com/users/AtwoodPa/followers',
  following_url: 'https://api.github.com/users/AtwoodPa/following{/other_user}',
  gists_url: 'https://api.github.com/users/AtwoodPa/gists{/gist_id}',
  starred_url: 'https://api.github.com/users/AtwoodPa/starred{/owner}{/repo}',
  subscriptions_url: 'https://api.github.com/users/AtwoodPa/subscriptions',
  organizations_url: 'https://api.github.com/users/AtwoodPa/orgs',
  repos_url: 'https://api.github.com/users/AtwoodPa/repos',
  events_url: 'https://api.github.com/users/AtwoodPa/events{/privacy}',
  received_events_url: 'https://api.github.com/users/AtwoodPa/received_events',
  type: 'User',
  site_admin: false,
  name: null,
  company: null,
  blog: '',
  location: null,
  email: null,
  hireable: null,
  bio: null,
  twitter_username: null,
  public_repos: 6,
  public_gists: 0,
  followers: 0,
  following: 3,
  created_at: '2022-08-06T13:02:16Z',
  updated_at: '2023-09-03T00:15:55Z'
}
authorization code: 4ea423f2ec1e04c6376a

成功执行上述流程,最终展示示例的welcome页面

Spring Boot整合OAuth2实现GitHub第三方登录-LMLPHP

到这里,Spring Boot整合GitHub实现第三方登录的实现就结束了,以此类推其他厂商的第三方登录实现流程也大概是这样。

10-26 02:25