Пользовательская страница входа Spring всегда помечает пользователя как анонимного

Я пытаюсь создать настраиваемую страницу входа в JSP для работы со Spring Security. Я последовал нескольким примерам, но после того, как я нажму кнопку отправки пользовательской страницы входа с действительными учетными данными, результатом всегда будет ошибка 403 Forbidden, хотя у пользователя есть правильный доступ в БД, и я могу успешно войти в систему с теми же учетными данными, если я удалил пользовательскую страницу входа .

Вот журналы

12:03:24,923 DEBUG [io.undertow.request] (default I/O-5) Matched prefix path /FitnessTracker for path /FitnessTracker/login.html
12:03:24,924 DEBUG [io.undertow.request.security] (default task-1) Attempting to authenticate /FitnessTracker/login.html, authentication required: false
12:03:24,925 DEBUG [io.undertow.request.security] (default task-1) Authentication outcome was NOT_ATTEMPTED with method io.undertow.security.impl.CachedAuthenticatedSessionMechanism@358df3b9 for /FitnessTracker/login.html
12:03:24,925 DEBUG [io.undertow.request.security] (default task-1) Authentication result was ATTEMPTED for /FitnessTracker/login.html
12:03:24,925 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
12:03:24,925 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
12:03:24,925 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] (default task-1) HttpSession returned null object for SPRING_SECURITY_CONTEXT
12:03:24,925 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] (default task-1) No SecurityContext was available from the HttpSession: io.undertow.servlet.spec.HttpSessionImpl@e399605d. A new one will be created.
12:03:24,925 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
12:03:24,925 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
12:03:24,925 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
12:03:24,925 DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] (default task-1) Request 'GET /login.html' doesn't match 'POST /logout
12:03:24,925 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
12:03:24,925 DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] (default task-1) Request 'GET /login.html' doesn't match 'POST /login.html
12:03:24,925 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
12:03:24,925 DEBUG [org.springframework.security.web.savedrequest.DefaultSavedRequest] (default task-1) pathInfo: both null (property equals)
12:03:24,925 DEBUG [org.springframework.security.web.savedrequest.DefaultSavedRequest] (default task-1) queryString: both null (property equals)
12:03:24,925 DEBUG [org.springframework.security.web.savedrequest.DefaultSavedRequest] (default task-1) requestURI: arg1=/FitnessTracker/; arg2=/FitnessTracker/login.html (property not equals)
12:03:24,925 DEBUG [org.springframework.security.web.savedrequest.HttpSessionRequestCache] (default task-1) saved request doesn't match
12:03:24,926 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
12:03:24,926 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
12:03:24,926 DEBUG [org.springframework.security.web.authentication.AnonymousAuthenticationFilter] (default task-1) Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@7b207c43: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 5KhX3tAA2iFK9bLF5nkrmmyaH1EQWcSGMRCpP_5N; Granted Authorities: ROLE_ANONYMOUS'
12:03:24,927 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
12:03:24,927 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
12:03:24,927 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
12:03:24,927 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] (default task-1) Secure object: FilterInvocation: URL: /login.html; Attributes: [permitAll]
12:03:24,927 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] (default task-1) Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@7b207c43: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: 5KhX3tAA2iFK9bLF5nkrmmyaH1EQWcSGMRCpP_5N; Granted Authorities: ROLE_ANONYMOUS
12:03:24,927 DEBUG [org.springframework.security.access.vote.AffirmativeBased] (default task-1) Voter: org.springframework.security.web.access.expression.WebExpressionVoter@7f7eaf3b, returned: 1
12:03:24,927 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] (default task-1) Authorization successful
12:03:24,927 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] (default task-1) RunAsManager did not change Authentication object
12:03:24,927 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /login.html reached end of additional filter chain; proceeding with original chain
12:03:24,928 DEBUG [org.springframework.web.servlet.DispatcherServlet] (default task-1) DispatcherServlet with name 'DispatcherServlet' processing GET request for [/FitnessTracker/login.html]
12:03:24,928 DEBUG [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] (default task-1) Looking up handler method for path /login.html
12:03:24,929 DEBUG [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] (default task-1) Returning handler method [public java.lang.String org.learning.spring.controller.LoginController.login()]
12:03:24,929 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (default task-1) Returning cached instance of singleton bean 'loginController'
12:03:24,929 DEBUG [org.springframework.web.servlet.DispatcherServlet] (default task-1) Last-Modified value for [/FitnessTracker/login.html] is: -1
12:03:24,929 DEBUG [org.springframework.web.servlet.DispatcherServlet] (default task-1) Rendering view [org.springframework.web.servlet.view.JstlView: name 'login'; URL [/WEB-INF/jsp/login.jsp]] in DispatcherServlet with name 'DispatcherServlet'
12:03:24,929 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (default task-1) Returning cached instance of singleton bean 'requestDataValueProcessor'
12:03:24,930 DEBUG [org.springframework.web.servlet.view.JstlView] (default task-1) Forwarding to resource [/WEB-INF/jsp/login.jsp] in InternalResourceView 'login'
12:03:24,930 DEBUG [org.apache.jasper.servlet] (default task-1) JspEngine --> /WEB-INF/jsp/login.jsp
12:03:24,930 DEBUG [org.apache.jasper.servlet] (default task-1)          ServletPath: /WEB-INF/jsp/login.jsp
12:03:24,930 DEBUG [org.apache.jasper.servlet] (default task-1)             PathInfo: null
12:03:24,930 DEBUG [org.apache.jasper.servlet] (default task-1)             RealPath: D:\Programs\Development\JAVA\Server\WildFly\wildfly-12.0.0.Final\standalone\tmp\vfs\temp\tempf4aa4a688921fb1a\FitnessTracker.war-9ab7386a6c27f7be\WEB-INF\jsp\login.jsp
12:03:24,930 DEBUG [org.apache.jasper.servlet] (default task-1)           RequestURI: /FitnessTracker/WEB-INF/jsp/login.jsp
12:03:24,930 DEBUG [org.apache.jasper.servlet] (default task-1)          QueryString: null
12:03:24,931 DEBUG [org.springframework.security.web.header.writers.HstsHeaderWriter] (default task-1) Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@6c23b3f5
12:03:24,931 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] (default task-1) SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
12:03:24,932 DEBUG [org.springframework.web.servlet.DispatcherServlet] (default task-1) Successfully completed request
12:03:24,932 DEBUG [org.springframework.security.web.access.ExceptionTranslationFilter] (default task-1) Chain processed normally
12:03:24,932 DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] (default task-1) SecurityContextHolder now cleared, as request processing completed
12:03:27,686 DEBUG [io.undertow.request] (default I/O-5) Matched prefix path /FitnessTracker for path /FitnessTracker/j_spring_security_check
12:03:27,687 DEBUG [io.undertow.request.security] (default task-1) Attempting to authenticate /FitnessTracker/j_spring_security_check, authentication required: false
12:03:27,687 DEBUG [io.undertow.request.security] (default task-1) Authentication outcome was NOT_ATTEMPTED with method io.undertow.security.impl.CachedAuthenticatedSessionMechanism@358df3b9 for /FitnessTracker/j_spring_security_check
12:03:27,687 DEBUG [io.undertow.request.security] (default task-1) Authentication result was ATTEMPTED for /FitnessTracker/j_spring_security_check
12:03:27,687 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /j_spring_security_check at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
12:03:27,688 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /j_spring_security_check at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
12:03:27,688 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] (default task-1) HttpSession returned null object for SPRING_SECURITY_CONTEXT
12:03:27,688 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] (default task-1) No SecurityContext was available from the HttpSession: io.undertow.servlet.spec.HttpSessionImpl@e399605d. A new one will be created.
12:03:27,688 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /j_spring_security_check at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
12:03:27,688 DEBUG [org.springframework.security.web.FilterChainProxy] (default task-1) /j_spring_security_check at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
12:03:27,688 DEBUG [org.springframework.security.web.csrf.CsrfFilter] (default task-1) Invalid CSRF token found for http://localhost:8080/FitnessTracker/j_spring_security_check
12:03:27,688 DEBUG [org.springframework.security.web.header.writers.HstsHeaderWriter] (default task-1) Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@6c23b3f5
12:03:27,688 DEBUG [org.springframework.security.web.context.HttpSessionSecurityContextRepository] (default task-1) SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
12:03:27,688 DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] (default task-1) SecurityContextHolder now cleared, as request processing completed

Это конфигурация безопасности

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/**")
                .hasRole("USER")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login.html")
                .permitAll();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        JdbcDaoImpl jdbcDao = new JdbcDaoImpl();
        jdbcDao.setDataSource(dataSource);
        return jdbcDao;
    }

    @Bean
    public static PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Мой контроллер входа в систему

@Controller
public class LoginController {

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login() {
        return "login";
    }
}

Страница входа в систему

<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<form action = "j_spring_security_check" name = "f" method = "post">
    <table>
        <tr>
            <td>User:</td>
            <td><input type = "text" name = "j_username" value = ""></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type = "password" name = "j_password" ></td>
        </tr>
        <tr>
            <td colspan = "2"><input type = "submit" name = "Submit" value = "Submit"></td>
        </tr>
    </table>
</form>
</body>
</html>

Это мои зависимости безопасности в файле POM:

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

Мой веб-инициализатор

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        WebApplicationContext context = getContext();

        servletContext.addListener(new ContextLoaderListener(context));

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("*.html");
        dispatcher.addMapping("*.json");
        dispatcher.addMapping("/pdfs/**");
        dispatcher.addMapping("/images/**");
    }

    private AnnotationConfigWebApplicationContext getContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(WebConfig.class);
        return context;
    }
}

И WebConfig [он не содержит ничего, связанного с безопасностью, он просто содержит конфигурацию источника данных, диспетчер сущностей, преобразователи представлений и т. д.]

@EnableWebMvc
@Configuration
@EnableTransactionManagement
@ComponentScan("org.learning.spring")
@EnableJpaRepositories("org.learning.spring.repository")
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public DriverManagerDataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl("jdbc:postgresql://localhost:5432/FitnessTracker");
        dataSource.setUsername("postgres");
        dataSource.setPassword("sa");

        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();

        entityManagerFactoryBean.setPersistenceUnitName("punit");
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setJpaVendorAdapter(hibernateJpaVendorAdapter());
        entityManagerFactoryBean.setJpaPropertyMap(getJPAPropertyMap());
        entityManagerFactoryBean.setPackagesToScan(new String[]{"org.learning.spring"});

        return entityManagerFactoryBean;
    }

    @Bean
    public HibernateJpaVendorAdapter hibernateJpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setShowSql(true);
        return hibernateJpaVendorAdapter;
    }

    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
        jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
        return jpaTransactionManager;
    }

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
        internalResourceViewResolver.setPrefix("/WEB-INF/jsp/");
        internalResourceViewResolver.setSuffix(".jsp");
        return internalResourceViewResolver;
    }

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        return messageSource;
    }

    @Bean
    public SessionLocaleResolver localeResolver() {
        SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
        sessionLocaleResolver.setDefaultLocale(Locale.ENGLISH);
        return sessionLocaleResolver;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
        localeChangeInterceptor.setParamName("language");
        registry.addInterceptor(localeChangeInterceptor);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/assets/**").addResourceLocations("/assets/");
        registry.addResourceHandler("/pdfs/**").addResourceLocations("/pdfs/");
    }

    private Map<String, String> getJPAPropertyMap() {
        Map<String, String> jpaPropertyMap = new HashMap<>();
        jpaPropertyMap.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        jpaPropertyMap.put("hibernate.hbm2ddl.auto", "update");
        jpaPropertyMap.put("hibernate.format_sql", "true");
        return jpaPropertyMap;
    }
}

Вы действительно читали журнал? Эта строчка 12:03:27,688 DEBUG [org.springframework.security.web.csrf.CsrfFilter] (default task-1) Invalid CSRF token found for http://localhost:8080/FitnessTracker/j_spring_security_check в значительной степени говорит о том, что не так. Вы включили защиту CSRF, но не включаете ее при входе в систему.

M. Deinum 02.05.2018 13:28

Да, я проверял и пытался отключить его раньше, но это не помогло, так как отсутствовала вторая часть исправления. [Я написал шаг, который я предпринял, чтобы исправить это ниже]

Tocka Ayman 02.05.2018 15:06
1
2
903
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поскольку версия spring-security 4.x по умолчанию, login-processing-url больше не j_spring_security_check, а просто login. Вы можете проверить в Справочник по безопасности Spring 5.0.4-RELEASE.

Поэтому измените действие формы входа на вход в jsp:

<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<form action = "login" name = "f" method = "post">
    <table>
        <tr>
            <td>User:</td>
            <td><input type = "text" name = "j_username" value = ""></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type = "password" name = "j_password" ></td>
        </tr>
        <tr>
            <td colspan = "2"><input type = "submit" name = "Submit" value = "Submit"></td>
        </tr>
    </table>
</form>
</body>
</html>

И учитывая, что вы установили это сопоставление с диспетчером-сервлетом:

ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.html");
dispatcher.addMapping("*.json");
dispatcher.addMapping("/pdfs/**");
dispatcher.addMapping("/images/**");

Ваш контроллер должен быть сопоставлен с суффиксом '.html':

@Controller
public class LoginController {

    @RequestMapping(value = "/login.html", method = RequestMethod.GET)
    public String login() {
        return "login";
    }
}

Спасибо Jlumietu и ​​M. Deinum, вы оба действительно спасли мне день.

Что я на самом деле сделал, чтобы это работало, так это

Сначала я отключил CSRF, поэтому моя конфигурация безопасности http стала такой:

http
.authorizeRequests()
.antMatchers("/**")
.hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.permitAll()
.and().csrf().disable()
;

Во-вторых, я изменил URL-адрес обработки входа [с j_spring_security_check на логин], параметр имени пользователя [с j_username на имя пользователя] и параметр пароля [с j_password на passwrod] в файле login.jsp.

Также я использовал тимелеаф для отправки формы как https://docs.spring.io/spring-security/site/docs/current/guides/html5/form-javaconfig.html. Итак, login.jsp стал таким

<html xmlns:th = "http://www.thymeleaf.org">
<body>
<form th:action = "login" name = "f" 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 colspan = "2"><input type = "submit" name = "Submit" value = "Submit"></td>
        </tr>
    </table>
</form>
</body>
</html>

Другие вопросы по теме