好朋友。我使用Spring-web,-mvc等版本4.1.x和spring-secure版本4.0.0,我有一个奇怪的问题。
我有LoginController.java和@RequestMapping(" / login")返回"登录",映射到login.jsp。我还有带有下一个设置的security-config.xml文件
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="John" authorities="admin"
password="letmein" />
<security:user name="Zog" authorities="admin"
password="iamzog" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:http use-expressions="true">
<security:csrf disabled="true"></security:csrf>
<security:intercept-url pattern="/createoffer" access="isAuthenticated()" />
<security:intercept-url pattern="/docreate" access="isAuthenticated()" />
<security:intercept-url pattern="/offercreated" access="isAuthenticated()" />
<security:intercept-url pattern="/" access="permitAll" />
<security:intercept-url pattern="/login" access="permitAll" />
<security:intercept-url pattern="/static/**" access="permitAll" />
<security:intercept-url pattern="/offers" access="permitAll" />
<security:intercept-url pattern="/**" access="denyAll" />
<security:form-login login-page="/login"
login-processing-url="/login"
username-parameter="username"
password-parameter="password"
default-target-url="/"
authentication-failure-url="/login?error=true"/>
</security:http>
当我尝试打开/登录时,弹出显示默认登录表单,我的LoginController方法不会执行。但是当我在这个登录表单中输入错误的数据时,spring会将我重定向到/ login?error = true并且LoginController捕获这个并重定向到我的login.jsp。所以,spring在我的控制器之前捕获/登录,但是传递/登录?error = true到控制器并且我的自定义登录表单没有正常工作。
我的web.xml文件如下所示
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<description>MySQL Test App</description>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-security-config.xml
classpath:dao-context.xml
classpath:service-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>offers</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>offers</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/spring</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
来自春季课程网站的人提出同样的问题,但唯一的答案是使用spring-security 3.x.x&#39;。我不想使用3x安全性,但想要了解弹簧的魔力在哪里被打破。谢谢你提前。
答案 0 :(得分:1)
这是Spring Security 4中的一个错误,记录为SEC-2919。它将在Spring Security 4.0.1中修复,将于下周发布。
<强>变通方法强>
以下是一些解决方法。您可以在4.0.1发布后删除解决方法(预计大约一周)。
使用其他网址
最简单的解决方法是使用&#34; / login&#34;以外的网址。例如,您可以使用&#34; / authenticate&#34;。
<http ...>
<form-login login-page="/authenticate" ... />
</http>
使用BeanPostProcessor
或者,以下BeanDefinitionRegistryPostProcessor
将通过删除DefaultLoginPageGeneratingFilter
来解决问题。要使用它,只需确保将BeanDefinitionRegistryPostProcessor
注册为Bean。
例如,创建一个类似于以下内容的类:
package sample;
import java.util.Iterator;
import java.util.List;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
public class Sec2919PostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
throws BeansException {
String[] beanDefinitionNames = registry.getBeanDefinitionNames();
for(String name : beanDefinitionNames) {
BeanDefinition beanDefinition = registry.getBeanDefinition(name);
if(beanDefinition.getBeanClassName().equals(DefaultSecurityFilterChain.class.getName())) {
List<Object> filters = (List<Object>) beanDefinition.getConstructorArgumentValues().getArgumentValue(1, List.class).getValue();
Iterator<Object> iFilters = filters.iterator();
while(iFilters.hasNext()) {
Object f = iFilters.next();
if(f instanceof BeanDefinition) {
BeanDefinition bean = (BeanDefinition) f;
if(bean.getBeanClassName().equals(DefaultLoginPageGeneratingFilter.class.getName())) {
iFilters.remove();
}
}
}
}
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
}
}
然后添加bean定义:
<bean class="sample.Sec2919PostProcessor"/>