Search code examples
springspring-mvcspring-security

Spring Security 404


when I run my app, I encounter a problem (404 not found). But without the classes SpringConfig and SecurityInitializer, my app works.

it's SecurityConfig

package basic;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
        auth.inMemoryAuthentication().withUser(userBuilder.username("Yehor").password("1111").roles("EMPLOYEE"));
        auth.inMemoryAuthentication().withUser(userBuilder.username("Maria").password("2222").roles("HR"));
        auth.inMemoryAuthentication().withUser(userBuilder.username("Yan").password("3333").roles("MANAGER", "HR"));
    }
}

It's SecurityInitializer

package basic;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}

It's MyController

package basic;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MyController {
    @RequestMapping("/")
    @ResponseBody
    public ModelAndView getInfoForAllEmps(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("view_for_all");
        return modelAndView;
    }
    @GetMapping("/hr-info")
    public String getInfoHr() {
        return "view_for_hr";
    }
    @GetMapping("/manager-info")
    public String getInfoManager() {
        return "view_for_manager";
    }
}

It's WebDisp

package basic;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebDisp extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{Congif.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

It's Congif

package basic;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@ComponentScan(basePackages = "basic")
public class Congif {
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
        internalResourceViewResolver.setPrefix("/WEB-INF/view/");
        internalResourceViewResolver.setSuffix(".jsp");
        return internalResourceViewResolver;
    }
}

It's pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.spring.secutry</groupId>
  <artifactId>untitled7</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>untitled7 Maven Webapp</name>
  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->

    <dependency>
      <groupId>jakarta.servlet</groupId>
      <artifactId>jakarta.servlet-api</artifactId>
      <version>6.0.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.annotation</groupId>
      <artifactId>jakarta.annotation-api</artifactId>
      <version>2.1.1</version>
    </dependency>


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

    <!-- Spring Web MVC -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.9.RELEASE</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>untitled7</finalName>
  </build>
</project>

I did try change dependencies versions in pom.xml Pleaseeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee can you help me


Solution

  • Spring 5 and Tomcat 9 do not work with jakarata imports, but javax instead. Spring 6 works with Tomcat 10 but does not work with javax, but jakarta instead. Having any jakarta dependency/imports in your Spring 5/Tomcat 9 application will cause your application to fail.

    So with that in mind:

    Spring 5 + Tomcat 9 = javax imports
    
    Spring 6 + Tomcat 10 = jakarta imports
    

    I refactored your classes and pom.xml to meet those requirements:

    Congif.java

    package basic;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.view.InternalResourceViewResolver;
    
    @Configuration
    @ComponentScan(basePackages = "basic")
    public class Congif {
        @Bean
        public InternalResourceViewResolver viewResolver() {
            InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
            internalResourceViewResolver.setPrefix("/WEB-INF/view/");
            internalResourceViewResolver.setSuffix(".jsp");
            return internalResourceViewResolver;
        }
    }
    

    MyController.java

    package basic;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.servlet.ModelAndView;
    
    @Controller
    public class MyController {
        @RequestMapping("/")
        @ResponseBody
        public ModelAndView getInfoForAllEmps(){
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("view_for_all");
            return modelAndView;
        }
        @GetMapping("/hr-info")
        public String getInfoHr() {
            return "view_for_hr";
        }
        @GetMapping("/manager-info")
        public String getInfoManager() {
            return "view_for_manager";
        }
    }
    

    SecurityConfig.java

    package basic;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.User.UserBuilder;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            UserBuilder userBuilder = User.withDefaultPasswordEncoder();
            auth.inMemoryAuthentication().withUser(userBuilder.username("Yehor").password("1111").roles("EMPLOYEE"));
            auth.inMemoryAuthentication().withUser(userBuilder.username("Maria").password("2222").roles("HR"));
            auth.inMemoryAuthentication().withUser(userBuilder.username("Yan").password("3333").roles("MANAGER", "HR"));
        }
    }
    

    SecurityInitializer.java

    package basic;
    
    import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
    
    public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
    }
    

    WebDisp.java

    package basic;
    
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    public class WebDisp extends AbstractAnnotationConfigDispatcherServletInitializer {
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return null;
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{Congif.class};
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    }
    

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>yes</groupId>
      <artifactId>yes</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>war</packaging>
     <properties>
            <springframework.version>5.0.2.RELEASE</springframework.version>
            <springsecurity.version>5.0.0.RELEASE</springsecurity.version>
    
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
        </properties>
    
        <dependencies>
    
            <!-- Spring MVC support -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${springframework.version}</version>
            </dependency>
    
            <!-- Spring Security -->
            <!-- spring-security-web and spring-security-config -->
            
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-web</artifactId>
                <version>${springsecurity.version}</version>
            </dependency>
            
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-config</artifactId>
                <version>${springsecurity.version}</version>
            </dependency>   
            
            <!-- Servlet, JSP and JSTL support -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
            </dependency>
    
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>javax.servlet.jsp-api</artifactId>
                <version>2.3.1</version>
            </dependency>
    
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
      
        <!-- TO DO: Add support for Maven WAR Plugin -->
    
        <build>
            <finalName>spring-security-demo</finalName>
        
            <pluginManagement>
                <plugins>
                    <plugin>
                        <!-- Add Maven coordinates (GAV) for: maven-war-plugin -->
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-war-plugin</artifactId>
                        <version>3.2.0</version>                    
                    </plugin>                       
                </plugins>
            </pluginManagement>
        </build>
      
    </project>
    

    If withDefaultPasswordEncoder deprecated method bothers you, you can use the following code:

    package basic;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                .withUser("Yehor").password(passwordEncoder().encode("1111")).roles("EMPLOYEE")
                .and()
                .withUser("Maria").password(passwordEncoder().encode("2222")).roles("HR")
                .and()
                .withUser("Yan").password(passwordEncoder().encode("3333")).roles("MANAGER", "HR");
        }
    }
    

    In this refactored version, BCryptPasswordEncoder is used to encode passwords before storing them. The passwordEncoder() method is annotated with @Bean, which makes it available as a bean for dependency injection. Each password is encoded using this encoder before being stored.