spring - Spring自定义登录页面始终将用户标记为匿名
问题描述
我正在尝试制作一个自定义 JSP 登录页面以使用 Spring Security。我遵循了多个示例,但是在使用有效凭据按下自定义登录页面的提交按钮后,结果始终是 403 Forbidden 错误,尽管用户在 DB 中具有正确的访问权限,并且如果我删除了自定义登录页面,我可以使用相同的凭据成功登录.
这是日志
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;
}
}
解决方案
由于spring-security
4.x 版本默认login-processing-url
不再j_spring_security_check
是login
. 您可以查看Spring Security Reference 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>
并且假设您已将此映射设置为 dispatcher-servlet:
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";
}
}
推荐阅读
- react-native - 我可以在 React-Native 中创建带有播放/暂停按钮的自定义通知吗?
- c - 关于变量不是通过 %p 打印的指针
- reactjs - Where am i going wrong with using typescript and redux to retrieve the stores data?
- excel - 如何在excel中堆叠或转换数据
- regex - 如何将文件名的一部分移动到不同的位置
- tableau-api - 我们如何在 Tableau 中添加 Alter 会话查询以提高性能
- r - Knit 无法安装软件包
- java - 客户端发送的 HTTP 状态 400 请求在语法上不正确 Spring mvc 项目
- node.js - 在 Node.js 中使用集群时出错
- java - 在 Java Flink 作业中使用 Python 用户定义函数