1. 概述

本文将介绍如何用Spring Security保护Jakarta EE Web应用。通过Java配置和XML配置两种方式,实现基础认证、角色授权和自定义登录流程等安全功能。

2. Maven依赖

首先添加核心Spring Security依赖:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.7.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.7.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>5.7.5</version>
</dependency>

当前最新版本为5.7.5,可通过Maven Central获取最新版本。

3. 安全配置

创建基础安全配置类:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User.withUsername("user1")
            .password("{noop}user1Pass")
            .roles("USER")
            .build();
        UserDetails admin = User.withUsername("admin")
            .password("{noop}adminPass")
            .roles("ADMIN")
            .build();
        return new InMemoryUserDetailsManager(user, admin);
    }
}

关键点说明

  • 使用内存存储实现快速原型开发
  • {noop}前缀表示明文密码(生产环境需加密)
  • 硬编码用户信息仅用于演示

通过SecurityWebApplicationInitializer加载配置:

public class SecurityWebApplicationInitializer
  extends AbstractSecurityWebApplicationInitializer {

    public SecurityWebApplicationInitializer() {
        super(SpringSecurityConfig.class);
    }
}

此时已实现基础安全控制:所有请求默认需要认证。

4. 配置安全规则

通过SecurityFilterChain自定义安全策略:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf()
        .disable()
        .authorizeRequests()
        .antMatchers("/auth/login*")
        .anonymous()
        .antMatchers("/home/admin*")
        .hasRole("ADMIN")
        .anyRequest()
        .authenticated()
        .and()
        .formLogin()
        .loginPage("/auth/login")
        .defaultSuccessUrl("/home", true)
        .failureUrl("/auth/login?error=true")
        .and()
        .logout()
        .logoutSuccessUrl("/auth/login");
    return http.build();
}

4.1 自定义登录页

通过formLogin()指定登录页:

http.formLogin()
  .loginPage("/auth/login")

未指定时Spring Security提供默认登录页(/login):

<html>
<head></head>
<body>
<h1>Login</h1>
<form name='f' action="/auth/login" method='POST'>
    <table>
        <tr>
            <td>User:</td>
            <td><input type='text' name='username' value=''></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type='password' name='password'/></td>
        </tr>
        <tr>
            <td><input name="submit" type="submit" 
              value="submit"/></td>
        </tr>
    </table>
</form>
</body>
</html>

4.2 自定义着陆页

配置登录成功后的跳转逻辑:

http.formLogin()
  .defaultSuccessUrl("/home", true)

⚠️ 参数说明

  • alwaysUse=true:始终跳转到指定URL
  • alwaysUse=false(默认):优先跳转到原始请求页

配置登录失败页:

http.formLogin()
  .failureUrl("/auth/login?error=true")

4.3 授权控制

按角色限制接口访问:

.antMatchers("/home/admin*").hasRole("ADMIN")

非管理员访问/home/admin接口会收到403错误。

在JSP中实现视图级权限控制:

<%@ taglib prefix="security" 
  uri="http://www.springframework.org/security/tags" %>

<security:authorize access="hasRole('ADMIN')">
    This text is only visible to an admin
    <br/>
    <a href="<c:url value="/home/admin" />">Admin Page</a>
    <br/>
</security:authorize>

5. Spring Security XML配置

web/WEB-INF/spring/security.xml中配置:

5.1 认证管理器配置

基础认证配置:

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="user" 
              password="user123" 
              authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>

带密码编码器的配置:

<authentication-manager>
    <authentication-provider>
        <password-encoder hash="sha"/>
        <user-service>
            <user name="user"
              password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f" 
              authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>

5.2 安全规则配置

<http auto-config='true' use-expressions="true">
    <form-login default-target-url="/secure.jsp" />
    <intercept-url pattern="/" access="isAnonymous()" />
    <intercept-url pattern="/index.jsp" access="isAnonymous()" />
    <intercept-url pattern="/secure.jsp" access="hasRole('ROLE_USER')" />
</http>

配置说明

  • auto-config='true'启用默认安全行为
  • /secure.jsp需要ROLE_USER权限
  • 首页允许匿名访问

5.3 集成到web.xml

<context-param>                                                                           
    <param-name>contextConfigLocation</param-name>                                        
    <param-value>                                                                         
      /WEB-INF/spring/*.xml                                                             
    </param-value>                                                                        
</context-param>                                                                          
                                                                                          
<filter>                                                                                  
    <filter-name>springSecurityFilterChain</filter-name>                                  
    <filter-class>
      org.springframework.web.filter.DelegatingFilterProxy</filter-class>     
</filter>                                                                                 
                                                                                          
<filter-mapping>                                                                          
    <filter-name>springSecurityFilterChain</filter-name>                                  
    <url-pattern>/*</url-pattern>                                                         
</filter-mapping>                                                                         
                                                                                          
<listener>                                                                                
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

避坑提示:同一应用中混用Java配置和XML配置可能导致冲突!

6. 总结

本文展示了在Jakarta EE应用中集成Spring Security的两种方式:

核心功能实现

  • 内存认证与角色授权
  • 自定义登录/失败页
  • 接口级和视图级权限控制
  • Java配置与XML配置对比

完整代码示例见GitHub仓库。生产环境建议使用持久化存储替代内存用户,并启用密码加密。


原始标题:Securing Jakarta EE with Spring Security