admin管理员组

文章数量:1530041

三方登录的方式想必大家都很熟悉,基本健全的网页都会整几个入口,比如日常的微信、QQ,金融的支付宝,音视频的抖音、快手,码农领域的Github、Gitee等。

作为功能测试,我们就随机取一个简单的三方授权Gitee来尝试下。由于最近ChhatGPT写代码也是很火,这次的测试主要是chatGPT主导,本人负责辅助实现和测试,不经感叹效率高、能力强!

  • 一、三方登录常规的原理和流程
  • 二、关于JustAuth
  • 三、搭建全流程
    • 3.1 前期准备:内网穿透
    • 3.2 前期准备:申请一个三方登录授权应用
    • 3.3 开发指南:引入组件
    • 3.4 开发指南:构建一个基本的授权登录框架
    • 3.5 JustAuth+Gitee的三方登录

一、三方登录常规的原理和流程

  1. 用户点击第三方登录按钮,跳转到第三方平台的授权页面。

  2. 用户在第三方平台的授权页面上登录,确认授权。跳转到本地的服务,组装参数配置(response_type/client_id/redirect_uri/state,不同三方参数名可能不同,性质类似),请求三方平台。

  3. 第三方平台验证用户身份,生成授权码或访问令牌(state-对应提交过去的唯一值,code/auth_code,不同三方参数名可能不同,性质类似)。

  4. 用户的浏览器重定向回原网站(根据提交的redirect_uri进行回调),并将授权码或访问令牌传递给原网站。

  5. 原网站使用授权码或访问令牌向第三方平台请求用户信息(用户ID、头像、昵称等)。

  6. 第三方平台返回用户信息给原网站。

  7. 原网站使用用户信息创建或更新本地用户账号,完成用户登录。

了解了基本思路之后,java开发的角度,肯定上来先找轮子(如果有要求要自己实现的话,也可以参考轮子的代码)

这边简单测试,选用了Spring Boot+ JustAuth + Thymeleaf (+ Spring Security 完全没有登录逻辑,可以不加) + IDEA + 内网穿透

以上组件,基本都比较熟悉,简单聊一下 JustAuth

二、关于JustAuth

JustAuth 是一个开源的 Java 三方登录集成工具,它可以帮助开发者快速集成第三方登录功能。

目前支持超过 20 种第三方平台的登录认证,包括但不限于:GitHub、Gitee、微信、QQ、微博、Google、Facebook、Twitter、LinkedIn 等。

使用 JustAuth 可以避免开发者需要针对每个第三方平台编写繁琐的登录认证代码,从而提高开发效率。

从2018年11月开始,一经发布就受到大量的支持,截止目前经过一个个开源人的伟大奉献,到2023年3月10日,JustAuth项目在Github已经有14.5K的star数,足以窥见它的成绩。

下面就借这轮子,一起学习了解下本地测试三方登录的实操流程。前后流程会比较长,请耐心看完。

三、搭建全流程

3.1 前期准备:内网穿透

关于本地开发工具IDEA这就不用多说了,关于使用其他开发工具都是可以的。

由于我们要本地对接公网做联调测试,所以需要内网穿透或者其他自己配置代理的方式都行。

我这边是之前使用购买的花生壳一个6块的域名,并且有送2个内网穿透的配置体验机会,所以就选择这个,这个产品做的也是比较好用。但是HTTP【为响应《网络安全法》,将于2022年6月9日开始,为您提供更安全的外网访问服务,暂停使用HTTP映射】。但是依旧可以配置HTTPS的访问方式,映射本地HTTP的端口都是可以的。

具体配置方式参考:https://service.oray/question/8156.html
我参照以上指南,是可以配置好一个公网可访问,代理本地127.0.0.1:8080的接口。

已经具备了以上条件后,继续往下走。

3.2 前期准备:申请一个三方登录授权应用

需要在你需要三方登录对应的平台上去申请三方登录的权限,这边拿Gitee举例。

Gitee官方OAuth的文档:https://gitee/api/v5/oauth_doc#/
其中包含:应用名称(随意)、应用描述(随意)、应用主页(随意)、应用回调地址(这是主要的,你自己服务可以回调的地址)、权限(按需选择)
填写好之后直接提交配置,就可以获取接口所需的client-id和client-secret。

  1. 在 修改资料 -> 第三方应用,创建要接入码云的应用。
  2. 填写应用相关信息,勾选应用所需要的权限。其中: 回调地址是用户授权后,码云回调到应用,并且回传授权码的地址。正常三方登录,勾选用户权限+个人邮箱信息基本就够了。
  3. 创建成功后,会生成 Cliend ID 和 Client Secret。他们将会在上述OAuth2 认证基本流程用到。

3.3 开发指南:引入组件

确定具备一个基本的java\maven的项目,在pom.xml中引入

  • Spring Boot
  • JustAuth
  • Thymeleaf
  • Spring Security 不需要其他认证,可以不加

这边为了测试偷懒,引入了【justauth-spring-boot-starter】,以下是测试的POM

<dependencies>
        <dependency>
            <groupId>com.xkcoding.justauth</groupId>
            <artifactId>justauth-spring-boot-starter</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 排除 Spring Boot 默认的日志依赖 -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <!-- Thymeleaf 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- Spring Security 安全框架 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>

3.4 开发指南:构建一个基本的授权登录框架

以下含非必须环节,不需要可自动过滤。

SpringSecurity身份验证,内置一个账号密码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/home").authenticated()
                .antMatchers("/oauth/**").permitAll()
                .anyRequest().permitAll()
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/home")
                .failureUrl("/login?error=true")
                .and()
                .logout()
                .logoutSuccessUrl("/login");
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER")
                .and()
                .withUser("admin").password("{noop}123456").roles("ADMIN");
    }
}

简单配备一个日志输出:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

简单配备一个登录页:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
<h1>Login</h1>
<div th:if="${param.error}">
    <p>Invalid username and password.</p>
</div>
<div th:if="${param.logout}">
    <p>You have been logged out.</p>
</div>
<form th:action="@{/login}" method="post">
    <div>
        <label for="username">Username:</label>
        <input type="text" id="username" name="username"/>
    </div>
    <div>
        <label for="password">Password:</label>
        <input type="password" id="password" name="password"/>
    </div>
    <div>
        <button type="submit">Login</button>
    </div>
</form>
<div>
    <a th:href="@{/oauth/login/gitee}">
        <img src="https://huashuimoyu/image/thirdlogo/gitee.png" width="40px" height="40px"/>
    </a>
</div>
</body>
</html>

简单配备一个登录跳转逻辑:

@Controller
public class HomeController {

    @GetMapping("/")
    public String home() {
        return "home";
    }

    @GetMapping("/home")
    public String home2() {
        return "home";
    }

    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @PostMapping("/login")
    public String loginWithUsenamePassword(String username,String password){
        System.out.println(username);
        System.out.println(password);
       return "success";
    }
}

到这边,使用Springboot+SpringSecurity 依靠登录框进行账号密码登录的基本流程可以通了,此外依赖花生壳一个映射的配置,使用公网一个https的访问路径就可以访问到这个登录页了。

3.5 JustAuth+Gitee的三方登录

下面接入JustAuth补充Gitee的三方登录
前面依赖已经引入了,使用自动装配,只要在application的配置文件配置下、书写确定的跳转和回调接口即可

justauth:
  enabled: true
  type:
    QQ:
    GITEE:
      client-id: 56ba1xxxxxx3c7d
      client-secret: 90c7xxxxxx129a97
      redirect-uri: https://exxxxxxxxn/oauth/gitee/callback #就你本地自己提供出去的登录跳转的API,注意是公网可访问的

使用JustAuth简单实现一个调用和回调:

刚才在登录页就简单用一张图片链接触发一个三方登录请求。

<div>
    <a th:href="@{/oauth/login/gitee}">
        <img src="https://huashuimoyu/image/thirdlogo/gitee.png" width="40px" height="40px"/>
    </a>
</div>

点击图片后,跳转到后端接口,后端接口组装认证参数,提交到Gitee接口。

    @GetMapping("/login/{type}")
    public void login(@PathVariable String type, HttpServletResponse response) throws IOException {
        AuthRequest authRequest = factory.get(type);
        response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
    }

请求Gitee,跳转到Gitee的授权登录页,选择想要授予的权限,点击确定。

确定后,Gitee就会将网址跳转到我们提交的redirect_url上,我们做出正确响应即可。

    @RequestMapping("/{type}/callback")
    public AuthResponse login(@PathVariable String type, AuthCallback callback) {
        AuthRequest authRequest = factory.get(type);
        AuthResponse response = authRequest.login(callback);
        System.out.println("【response】= {}"+JSON.toJSONString(response));
        return response;
    }

接口获取授权信息:

这个时候,我们的页面可以回到一个授权成功,正在登录页。我们可以在这个时候拿到Gitee用户的一些昵称、头像、uid这些信息,记录在自己网站中,后期可以直接认证。

本文标签: 干货三方账号流程JustAuth