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

Spring Security 6表单登录未创建登录控制器问题求助

Spring Security 6非Boot MVC项目默认表单登录404/405问题解决

问题背景

在Spring 6 MVC(非Boot)项目中集成Spring Security 6默认表单登录时,遇到以下问题:

  • 访问GET /login返回404错误,未生成预期的登录页面控制器
  • 自定义登录页提交表单到/login时返回405错误,登录请求未被正确处理

核心原因

Spring Boot会自动配置登录页面相关的控制器和资源,但非Boot MVC项目不会自动生成GET /login的控制器,同时需要手动确保Spring Security的登录处理过滤器能正确拦截POST /login请求。

解决方案

1. 修正Spring Security配置

修改SecurityConfig.java,明确允许访问登录页面,并配置登录处理路径:

package com.myapp.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception {
        return http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(requests -> requests
                        .requestMatchers("/login") // 允许匿名访问登录页面
                        .permitAll()
                        .requestMatchers("/secured")
                        .hasAnyRole("USER")
                        .anyRequest()
                        .authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login") // 指定登录页面路径
                        .loginProcessingUrl("/login") // 指定登录提交的处理路径,由Security过滤器处理
                        .permitAll()
                )
                .build();
    }
}

2. 手动编写登录页面控制器

创建处理GET /login的控制器,返回登录视图:

package com.myapp.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class LoginController {

    @GetMapping("/login")
    public String showLoginPage() {
        return "login"; // 对应视图文件名称,需确保视图解析器配置正确
    }
}

3. 创建登录页面视图

以Thymeleaf为例,在/WEB-INF/views/目录下创建login.html,表单提交路径指向/login:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <form th:action="@{/login}" method="post">
        <div>
            <label>用户名:<input type="text" name="username"></label>
        </div>
        <div>
            <label>密码:<input type="password" name="password"></label>
        </div>
        <button type="submit">登录</button>
    </form>
</body>
</html>

4. 确保MVC配置正确

配置Spring MVC的组件扫描和视图解析器,确保控制器和视图能被正确识别:

package com.myapp.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.myapp") // 扫描项目下的控制器、配置等组件
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine());
        resolver.setCharacterEncoding("UTF-8");
        registry.viewResolver(resolver);
    }

    private SpringTemplateEngine templateEngine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver());
        return engine;
    }

    private SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        resolver.setPrefix("/WEB-INF/views/"); // 视图文件前缀路径
        resolver.setSuffix(".html"); // 视图文件后缀
        resolver.setTemplateMode("HTML");
        resolver.setCharacterEncoding("UTF-8");
        return resolver;
    }
}

5. 注册Spring Security过滤器到Servlet容器

创建初始化类,自动注册Security过滤器链:

package com.myapp;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    // 无需额外代码,此类会自动将Security过滤器注册到Servlet容器
}

6. 配置DispatcherServlet初始化

创建Web应用初始化类,加载Spring配置:

package com.myapp;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.myapp.config.WebConfig;
import com.myapp.config.SecurityConfig;

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SecurityConfig.class}; // 根上下文加载Security配置
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class}; // Servlet上下文加载MVC配置
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"}; // 处理所有请求
    }
}

验证

  • 启动项目后访问GET /login,应能正常显示登录页面
  • 输入正确的用户名密码(需提前配置用户,比如在SecurityConfig中添加UserDetailsService Bean),提交后应能成功登录并访问/secured接口

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 00:05:43