PAC4J 新手入门,之二(框架引入)

对接目标及 pac4j 依赖

我们以对接 GitHub 进行实战,能从项目指定路径 /login/github 跳转 GitHub 认证后,获取登录用户的相关信息在界面展示,其他 API 配置为不受此认证限定。

项目中采用 Spring Security 进行认证对接,并使用 JEE 相关的 Filter 实现认证、回调跳转,所以我们需要引入相关依赖 spring-security-pac4j,版本选择 8.0.0;引入 JEE 依赖 javaee-pac4j,版本选择 7.1.0

然后我们需要引入 pac4j 核心依赖 pac4j-core,由于 6.0.0 版本还处于 RC,当前版本选择 5.7.0,同时,引入pac4j-javaee,以提供相关一些附加支持。(如果 Spring Boot 选择了 3.0.1 版本,将会引发 Tomcat 相关实现类的包名由 javax 变更为 jakaraeepac4j-javaee 也要变更为 pac4j-jakaratee,但由于很多其他组件还没有提供相应的支持,不建议选择这个版本。)

我们以 OAuth2.0 协议为例,引入相应的依赖 pac4j-oauth,版本与 pacj-core 一致,为 5.7.0

后面如果需要其他协议的对接,引入相应协议的依赖即可。

pom.xml

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 http://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.7</version>
        <relativePath/>
    </parent>

    <groupId>tech.bookhub</groupId>
    <artifactId>pac4j-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>pac4j-demo</name>
    <description>pac4j demo project for Spring Boot.</description>

    <properties>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-security-pac4j.version>8.0.0</spring-security-pac4j.version>
        <javaee-pac4j.version>7.1.0</javaee-pac4j.version>
        <pac4j.version>5.7.0</pac4j.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-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>spring-security-pac4j</artifactId>
            <version>${spring-security-pac4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-javaee</artifactId>
            <version>${pac4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>javaee-pac4j</artifactId>
            <version>${javaee-pac4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-core</artifactId>
            <version>${pac4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.pac4j</groupId>
            <artifactId>pac4j-oauth</artifactId>
            <version>${pac4j.version}</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

服务端配置

OAuth2.0 协议,在客户端进行认证对接前,我们需要在服务端配置客户端相关信息,然后获取服务端为客户端分配的认证信息。

我们以 GitHub 为例。我们进入 GitHub 官网 github.com/,登录账号后,点击网站右上角用户头像的下拉箭头,选择 "Settings",进入设置界面,然后选择 "Developer settings",最后选择 "OAuth Apps",最终页面链接为 github.com/settings/de...

我们点击"New OAuth App",进入 OAuth 应用新建页面,如下图所示:

我们按要求填入相应信息,需要注意在 GitHub 中,"Homepage URL" 代表应用,即客户端的主页地址;"Authorization callback URL" 则代表服务端调用客户端的回调 url,如果客户端正式发布后,需要配置为客户端真实的访问地址,由于我们是在本地测试,所以我们都暂填写 localhost 作为访问地址即可。

填写项 示例值
Homepage URL http://localhost:8888/
Authorization callback URL http://localhost:8888/callback?client_name=GitHubClient

此处注意 /callback?client_name=GitHubClient 我们为 pac4j 默认的标准回调地址实现,在实际项目中,我们还可以自定义。

填写信息示例如下图:

填写好后,我们点击 "Register application",完成客户端注册。然后我们得到 GitHub 作为服务端分配的认证信息,如下图所示:

我们记录下认证用信息 "Client ID",然后点击 "Generate a new client secert",生成一个 "Client Secret",如下图所示:

我们再记录下 "Client secret",用于客户端配置的认证信息就齐了。

添加认证接口

我们先创建一个新的 LoginController 类,用于实现触发登录认证的 API。

LoginController.java

java 复制代码
package tech.bookhub.controller;

import org.pac4j.core.profile.UserProfile;
import org.pac4j.jee.context.JEEContext;
import org.pac4j.jee.context.session.JEESessionStore;
import org.pac4j.springframework.security.profile.SpringSecurityProfileManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

@RestController
public class LoginController {
    @GetMapping("/login/github")
    public List<UserProfile> loginGithub(final HttpServletRequest request, final HttpServletResponse response) {
        final JEEContext jeeContext = new JEEContext(request, response);
        final SpringSecurityProfileManager profileManager = new SpringSecurityProfileManager(jeeContext, JEESessionStore.INSTANCE);
        return profileManager.getProfiles();
    }
}

API /login/github 的实现目标为:当认证通过后,此 API 响应登录到 GitHub 上的用户相关信息。

配置 pac4j

我们的项目作为客户端,需要配置 pac4j 以对接相应服务端的协议,由于服务端我们选择 GitHub 作为示例,那我们选择框架已实现的现成客户端 GitHubClient 进行配置。

我们先创建一个配置类,命名为 Pac4jConfig,并声明注解 @Configuration,然后在类中实现 pac4j Config 类的 Bean。

代码如下:

java 复制代码
package tech.bookhub.config;

import org.pac4j.core.config.Config;
import org.pac4j.oauth.client.GitHubClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Pac4jConfig {

    @Bean
    public Config config() {
        GitHubClient gitHubClient = new GitHubClient("a85f19ea0f51face127a", "84bf0695ea2a62674b8d5961a02a4c793bf23e2a");

        Clients clients = new Clients("http://localhost:8888/callback",gitHubClient);
        Config config = new Config(clients);
        return config;
    }
}

代码中可以看到,在服务端配置中获得的 Client IDClient secret 作为认证配置项,都传入了 GitHubClient 的构造函数。然后将生成的客户端对象传递给 Config 的构造函数。

配置 Security

指南未用 Spring Security 实现复杂的用户认证配置,仅用于 pac4j 的对接,所以我们先只关注认证的配置部分。

我们新建一个 SecurityConfig 类,用于存放相应的 SecurityFilterChain 的 Bean 定义,代码如下:

java 复制代码
package tech.bookhub.config;

import org.pac4j.core.config.Config;
import org.pac4j.jee.filter.CallbackFilter;
import org.pac4j.jee.filter.LogoutFilter;
import org.pac4j.jee.filter.SecurityFilter;
import org.pac4j.springframework.security.web.Pac4jEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

@EnableWebSecurity
public class SecurityConfig {
    @Configuration
    @Order(1)
    public static class CallbackWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private Config config;

        @Autowired
        private Pac4jEntryPoint pac4jEntryPoint;

        protected void configure(final HttpSecurity http) throws Exception {
            http.antMatcher("/callback")
                    .addFilterBefore(new CallbackFilter(config), BasicAuthenticationFilter.class)
                    .csrf().disable();
        }
    }


    @Configuration
    @Order(2)
    public static class LogoutWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private Config config;

        protected void configure(final HttpSecurity http) throws Exception {
            final LogoutFilter logoutFilter = new LogoutFilter(config, "/?defaulturlafterlogout");
            logoutFilter.setDestroySession(true);

            http.antMatcher("/pac4jLogout")
                    .addFilterBefore(logoutFilter, BasicAuthenticationFilter.class)
                    .csrf().disable();
        }
    }

    @Configuration
    @Order(3)
    public static class GitHubAuthAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private Config config;

        protected void configure(HttpSecurity http) throws Exception {
            final SecurityFilter filter = new SecurityFilter(config,"GitHubClient");

            http.antMatcher("/login/github")
                    .addFilterBefore(filter, BasicAuthenticationFilter.class)
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
        }
    }

    @Configuration
    @Order(4)
    public static class CommonAuthAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private Config config;

        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/login/**").authenticated()
                    .anyRequest().permitAll();
        }
    }
}

以上代码中,我们通过使用 JEE 相应的 SecurityFilter 用于认证判定,跳转相应的认证服务端,使用 CallbackFilter 接受服务端的回调请求,使用 LogoutFilter 实现退出登录的请求。

我们运行项目,在浏览器输入 http://localhost:8888/login/github,浏览器将跳转到 GitHub OAuth 认证界面,如下图:

我们输入自己的 GitHub 账号和密码,点击登录后,认证成功后,将会获得 /login/github 对应的响应数据,如下图:

如果我们在 GitHubClient 配置的 Client IDClient secret 不匹配,在认证成功后将会进入报错页面,如下图:

本文 Demo 见 GitHub,Demo 1

相关推荐
程序员爱钓鱼3 小时前
Rust 开发环境安装(Windows|macOS|Linux)
后端·rust
爱勇宝11 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒16 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码17 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo17 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志18 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..18 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects18 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰18 小时前
一些基础和问题解决
后端
陈随易18 小时前
前端项目部署只要30秒
前端·后端·程序员