简体   繁体   English

春季安全/登录重定向

[英]Spring-security /login redirecting

pals. 好朋友。 I'm using Spring-web, -mvc etc. version 4.1.x and spring-secure version 4.0.0 and I have strange issue. 我正在使用Spring-web,-mvc等版本4.1.x和spring-secure版本4.0.0,但我遇到了奇怪的问题。

I have LoginController.java with @RequestMapping("/login") returning "login", mapping to login.jsp. 我有LoginController.java,其中@RequestMapping(“ / login”)返回“ login”,映射到login.jsp。 Also I have security-config.xml file with next settings 我也有带有下一步设置的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>

When I try to open /login spring shows default login form and my LoginController's method isn't execute. 当我尝试打开/ login时,spring显示默认的登录表单,并且我的LoginController的方法未执行。 But when I enter wrong data in this login form, spring redirects me to /login?error=true and LoginController catches this and redirect to my login.jsp. 但是,当我在此登录表单中输入错误的数据时,spring将我重定向到/ login?error = true,而LoginController会捕获到该错误并重定向到我的login.jsp。 So, spring catches /login before my controller, but pass /login?error=true to controller and my custom login form isn't working correctly. 因此,spring在我的控制器之前捕获了/ login,但是将/ login?error = true传递给控制器​​,并且我的自定义登录表单无法正常工作。

My web.xml file looks like this 我的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>

People from site with spring course asks same question, but the only answer were 'use spring-security 3.x.x'. 春季课程现场的人都提出了同样的问题,但唯一的答案是“使用spring-security 3.x.x”。 I don't want to use 3x security, but want to understand where the magic of spring is broken. 我不想使用3倍安全性,但想了解弹簧的魔力在哪里被打破了。 Thank you for advance. 谢谢您的提前。

This is a bug in Spring Security 4 and is logged as SEC-2919 . 这是Spring Security 4中的一个错误,记录为SEC-2919 It will be fixed in Spring Security 4.0.1 which is due out next week. 它将在下周发布的Spring Security 4.0.1中修复。

Workarounds 解决方法

Below are a few workarounds. 以下是一些解决方法。 You can remove the workaround once 4.0.1 is released (expected in about a week). 您可以在发布4.0.1后(大约一周后)删除解决方法。

Use a Different URL 使用其他网址

The easiest workaround is to use a URL other than "/login". 最简单的解决方法是使用“ / login”以外的URL。 For example, you can use "/authenticate". 例如,您可以使用“ / authenticate”。

<http ...>
    <form-login login-page="/authenticate" ... />
</http>

Use a BeanPostProcessor 使用BeanPostProcessor

Alternatively, the following BeanDefinitionRegistryPostProcessor will fix the issue by removing the DefaultLoginPageGeneratingFilter . 另外,以下BeanDefinitionRegistryPostProcessor将通过删除DefaultLoginPageGeneratingFilter来解决此问题。 To use it simply ensure to register the BeanDefinitionRegistryPostProcessor as a Bean. 要使用它,只需确保将BeanDefinitionRegistryPostProcessor注册为Bean。

For example create a class that looks like the following: 例如,创建一个如下所示的类:

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 {
    }
}

Then add the bean definition: 然后添加bean定义:

<bean class="sample.Sec2919PostProcessor"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM