如何将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
相关产品推荐
相关产品推荐

