You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Shibboleth IDP集成至现有Spring应用并打包为单WAR部署至Jetty?

集成Shibboleth IDP到Spring Web应用并打包为单WAR部署至Jetty

核心思路

要同时复用现有Spring认证逻辑、让Shibboleth IDP便捷获取用户属性,且打包成单WAR,核心是把Shibboleth IDP的Web模块嵌入到Spring项目中,通过Spring认证体系做桥接,同时暴露属性查询接口供IDP调用。

步骤分解

1. 引入Shibboleth IDP依赖

在Spring项目的pom.xml(Maven)或build.gradle(Gradle)中添加Shibboleth IDP及Spring SAML2相关依赖,注意选择与Jetty兼容的版本:

<!-- Maven示例 -->
<dependencies>
    <!-- Shibboleth IDP核心依赖 -->
    <dependency>
        <groupId>org.opensaml</groupId>
        <artifactId>opensaml-core</artifactId>
        <version>4.1.1</version>
    </dependency>
    <dependency>
        <groupId>org.shibboleth.idp</groupId>
        <artifactId>idp-war</artifactId>
        <version>4.2.1</version>
        <type>war</type>
        <scope>provided</scope>
    </dependency>
    <!-- Spring Security SAML2桥接依赖 -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-saml2-service-provider</artifactId>
        <version>6.1.2</version>
    </dependency>
</dependencies>

2. 复用现有Spring认证逻辑

  • 扩展UserDetailsService,同时兼容原有认证和Shibboleth属性查询需求:
@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 复用原有逻辑加载用户
        User user = userRepo.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
        return new CustomUserPrincipal(user);
    }

    // 暴露给Shibboleth的属性查询方法
    public Map<String, Object> getUserAttributes(String username) {
        User user = userRepo.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
        Map<String, Object> attributes = new HashMap<>();
        attributes.put("email", user.getEmail());
        attributes.put("fullName", user.getFullName());
        attributes.put("roles", user.getRoles());
        return attributes;
    }
}
  • 配置Spring Security,同时保留原有认证入口并开放IDP属性查询端点:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        // 允许IDP服务调用属性接口(可配置专属认证增强安全性)
                        .requestMatchers("/idp/attributes/**").permitAll()
                        // 原有应用的认证规则
                        .anyRequest().authenticated()
                )
                // 保留原有认证方式(如表单登录)
                .formLogin(form -> form.loginPage("/login").permitAll())
                // 集成SAML2逻辑,桥接Shibboleth IDP
                .saml2Login(saml2 -> saml2.userDetailsService(userDetailsService));
        return http.build();
    }
}

3. 嵌入Shibboleth IDP配置

  • 在src/main/webapp/WEB-INF下创建idp/conf目录,复制Shibboleth IDP核心配置文件(如idp.properties、attribute-resolver.xml),修改attribute-resolver.xml使其调用Spring属性接口:
<!-- attribute-resolver.xml 示例 -->
<resolver:AttributeDefinition id="email" xsi:type="ad:Simple">
    <resolver:Dependency ref="userAttributeDataSource"/>
    <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:0.9.2342.19200300.100.1.3" friendlyName="email"/>
</resolver:AttributeDefinition>

<resolver:DataConnector id="userAttributeDataSource" xsi:type="dc:HTTP">
    <dc:URL>http://localhost:8080/idp/attributes/${username}</dc:URL>
    <dc:BasicAuth username="idp-service" password="your-secret-key"/>
</resolver:DataConnector>
  • 在web.xml中添加Shibboleth IDP的Servlet和过滤器,与Spring DispatcherServlet共存:
<web-app>
    <!-- Spring核心Servlet -->
    <servlet>
        <servlet-name>springDispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springDispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- Shibboleth IDP Servlet -->
    <servlet>
        <servlet-name>idpServlet</servlet-name>
        <servlet-class>org.shibboleth.idp.servlet.IdPServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>idpServlet</servlet-name>
        <url-pattern>/idp/*</url-pattern>
    </servlet-mapping>

    <!-- Shibboleth IDP过滤器 -->
    <filter>
        <filter-name>idpFilter</filter-name>
        <filter-class>org.shibboleth.idp.filter.IdPFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>idpFilter</filter-name>
        <servlet-name>idpServlet</servlet-name>
    </filter-mapping>
</web-app>

4. 打包为单WAR文件

  • Maven项目中修改pom.xml打包类型为war,配置maven-war-plugin合并Shibboleth资源:
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.3.2</version>
            <configuration>
                <webResources>
                    <resource>
                        <directory>src/main/webapp/WEB-INF/idp</directory>
                        <targetPath>WEB-INF/idp</targetPath>
                    </resource>
                </webResources>
            </configuration>
        </plugin>
    </plugins>
</build>
  • 执行mvn clean package生成单WAR文件,直接放入Jetty的webapps目录即可部署。

5. 验证与调试

  • 启动Jetty后,访问原有应用登录页,确认原有认证逻辑正常。
  • 配置测试SP发起SAML认证请求,验证Shibboleth IDP能否正确获取并返回用户属性。

内容的提问来源于stack exchange,提问作者zhongman zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:01:27