Spring Security 多點登錄點

Spring Security
Remote
0
12:37 AM · Nov 30 ,2025

1. 概述

在本快速教程中,我們將探討如何在 Spring Security 應用程序中定義多個入口點。

這主要涉及在 XML 配置文件的多個 http 塊或通過創建 SecurityFilterChain 豆類多次來創建多個 HttpSecurity 實例。

2. Maven 依賴項

為了開發,我們需要以下依賴項:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-web</artifactId> 
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>    
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <version>5.4.0</version>
</dependency>

最新版本的 spring-boot-starter-security, spring-boot-starter-web, spring-boot-starter-thymeleaf, spring-boot-starter-test, spring-security-test 可從 Maven Central 下載。

@Configuration @EnableWebSecurity public class MultipleEntryPointsSecurityConfig { @Bean public UserDetailsService userDetailsService() throws Exception { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User .withUsername("user") .password(encoder().encode("userPass")) .roles("USER").build()); manager.createUser(User .withUsername("admin") .password(encoder().encode("adminPass")) .roles("ADMIN").build()); return manager; } @Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(); } }

Now, let’s look at in our configurations.

When using Java configuration, the way to define multiple security realms is to have multiple to only allow users with a role of ADMIN and requires HTTP Basic Authentication with an entry point of type method:

   @Configuration
    @Order(1)
    public static class App1ConfigurationAdapter {

        @Bean
        public SecurityFilterChain filterChainApp1(HttpSecurity http) throws Exception {
            http.antMatcher("/admin/**")
                .authorizeRequests().anyRequest().hasRole("ADMIN")
                .and().httpBasic().authenticationEntryPoint(authenticationEntryPoint())
                .and().exceptionHandling().accessDeniedPage("/403");
            return http.build();
        }

        @Bean
        public AuthenticationEntryPoint authenticationEntryPoint(){
            BasicAuthenticationEntryPoint entryPoint = new  BasicAuthenticationEntryPoint();
            entryPoint.setRealmName("admin realm");
            return entryPoint;
        }
    }

The

The bean of type be set.

that can be accessed by regular users with a USER role using form authentication:

   @Configuration
    @Order(2)
    public static class App2ConfigurationAdapter {

        @Bean
        public SecurityFilterChain filterChainApp2(HttpSecurity http) throws Exception {
            http.antMatcher("/user/**")
                .authorizeRequests().anyRequest().hasRole("USER")
                .and().formLogin().loginProcessingUrl("/user/login")
                .failureUrl("/userLogin?error=loginError").defaultSuccessUrl("/user/myUserPage")
                .and().logout().logoutUrl("/user/logout").logoutSuccessUrl("/multipleHttpLinks")
                .deleteCookies("JSESSIONID")
                .and().exceptionHandling()
                .defaultAuthenticationEntryPointFor(loginUrlauthenticationEntryPointWithWarning(),  new AntPathRequestMatcher("/user/private/**"))
                .defaultAuthenticationEntryPointFor(loginUrlauthenticationEntryPoint(), new AntPathRequestMatcher("/user/general/**"))
                .accessDeniedPage("/403")
                .and().csrf().disable();
            return http.build();
        }
    }

As we can see, another way of defining entry points, besides the authenticationEntryPoint() method, is to use the object.

The and @Bean public AuthenticationEntryPoint loginUrlauthenticationEntryPoint(){ return new LoginUrlAuthenticationEntryPoint("/userLogin"); } @Bean public AuthenticationEntryPoint loginUrlauthenticationEntryPointWithWarning(){ return new LoginUrlAuthenticationEntryPoint("/userLoginWithWarning"); }

The main point here is how to set up these multiple entry points – not necessarily the implementation details of each one.

In this case, the entry points are both of type for a simple login page and private URLs.

This configuration will also require defining the MVC mappings and two pages with a standard login form.

For the form authentication, it’s very important to remember that any URL necessary for the configuration, such as the login processing URL also needs to follow the URL if a user without the appropriate role attempts to access a protected URL.

that will allow all types of users, including unauthenticated ones:

   @Configuration
    @Order(3)
    public static class App3ConfigurationAdapter {

        @Bean
        public SecurityFilterChain filterChainApp3(HttpSecurity http) throws Exception {
            http.antMatcher("/guest/**")
                .authorizeRequests()
                .anyRequest()
                .permitAll();
            return http.build();
        }
    }

instances in the previous section.

As expected, this will contain three separate XML URLs the XML configuration will use the element:

<security:http pattern="/admin/**" use-expressions="true" auto-config="true">
    <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
    <security:http-basic entry-point-ref="authenticationEntryPoint" />
</security:http>

<bean id="authenticationEntryPoint"
  class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
     <property name="realmName" value="admin realm" />
</bean>

Of note here is that if using XML configuration, the roles have to be of the form URLs will have to be broken up into two http blocks in xml because there is no direct equivalent to the <security:http pattern="/user/general/**" use-expressions="true" auto-config="true" entry-point-ref="loginUrlAuthenticationEntryPoint"> <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> //form-login configuration </security:http> <bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <constructor-arg name="loginFormUrl" value="/userLogin" /> </bean>

For the <security:http pattern="/user/private/**" use-expressions="true" auto-config="true" entry-point-ref="loginUrlAuthenticationEntryPointWithWarning"> <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/> //form-login configuration </security:http> <bean id="loginUrlAuthenticationEntryPointWithWarning" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <constructor-arg name="loginFormUrl" value="/userLoginWithWarning" /> </bean>

For the <security:http pattern="/**" use-expressions="true" auto-config="true"> <security:intercept-url pattern="/guest/**" access="permitAll()"/> </security:http>

Also important here is that at least one XML

@Controller
public class PagesController {

    @GetMapping("/admin/myAdminPage")
    public String getAdminPage() {
        return "multipleHttpElems/myAdminPage";
    }

    @GetMapping("/user/general/myUserPage")
    public String getUserPage() {
        return "multipleHttpElems/myUserPage";
    }

    @GetMapping("/user/private/myPrivateUserPage")
    public String getPrivateUserPage() {
        return "multipleHttpElems/myPrivateUserPage"; 
    }

    @GetMapping("/guest/myGuestPage")
    public String getGuestPage() {
        return "multipleHttpElems/myGuestPage";
    }

    @GetMapping("/multipleHttpLinks")
    public String getMultipleHttpLinksPage() {
        return "multipleHttpElems/multipleHttpLinks";
    }
}

<a th:href="@{/admin/myAdminPage}">Admin page</a> <a th:href="@{/user/general/myUserPage}">User page</a> <a th:href="@{/user/private/myPrivateUserPage}">Private user page</a> <a th:href="@{/guest/myGuestPage}">Guest page</a>

Welcome admin! <a th:href="@{/multipleHttpLinks}" >Back to links</a>

@SpringBootApplication
public class MultipleEntryPointsApplication {
    public static void main(String[] args) {
        SpringApplication.run(MultipleEntryPointsApplication.class, args);
    }
}

@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = MultipleEntryPointsApplication.class)
public class MultipleEntryPointsTest {
 
    @Autowired
    private WebApplicationContext wac;

    @Autowired
    private FilterChainProxy springSecurityFilterChain;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
          .addFilter(springSecurityFilterChain).build();
    }
}

@Test public void whenTestAdminCredentials_thenOk() throws Exception { mockMvc.perform(get("/admin/myAdminPage")).andExpect(status().isUnauthorized()); mockMvc.perform(get("/admin/myAdminPage") .with(httpBasic("admin", "adminPass"))).andExpect(status().isOk()); mockMvc.perform(get("/user/myUserPage") .with(user("admin").password("adminPass").roles("ADMIN"))) .andExpect(status().isForbidden()); }

@Test public void whenTestUserCredentials_thenOk() throws Exception { mockMvc.perform(get("/user/general/myUserPage")).andExpect(status().isFound()); mockMvc.perform(get("/user/general/myUserPage") .with(user("user").password("userPass").roles("USER"))) .andExpect(status().isOk()); mockMvc.perform(get("/admin/myAdminPage") .with(user("user").password("userPass").roles("USER"))) .andExpect(status().isForbidden()); }

@Test
public void givenAnyUser_whenGetGuestPage_thenOk() throws Exception {
    mockMvc.perform(get("/guest/myGuestPage")).andExpect(status().isOk());

    mockMvc.perform(get("/guest/myGuestPage")
      .with(user("user").password("userPass").roles("USER")))
      .andExpect(status().isOk());

    mockMvc.perform(get("/guest/myGuestPage")
      .with(httpBasic("admin", "adminPass")))
      .andExpect(status().isOk());
}

5. 結論

在本教程中,我們演示瞭如何配置多個入口點,當使用 Spring Security 時。

請注意,使用 HTTP Basic Authentication 時無法註銷,因此您需要關閉並重新打開瀏覽器以清除身份驗證。

要運行 JUnit 測試,請使用定義的 Maven 配置文件 entryPoints,如下所示:

mvn clean install -PentryPoints

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.