Spring Security自定义过滤器

8

我希望自定义Spring Security 3.0.5并将登录URL更改为/login而不是/j_spring_security_check。

我需要做的是允许在"/"目录下登录,并保护"/admin/report.html"页面。

首先,我使用教程和Spring Security源代码创建了自己的过滤器:

public class MyFilter extends AbstractAuthenticationProcessingFilter {
    private static final String DEFAULT_FILTER_PROCESSES_URL = "/login";
    private static final String POST = "POST";
    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
    public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";

    private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
    private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;

    protected MyFilter() {
        super(DEFAULT_FILTER_PROCESSES_URL);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) 
                          throws AuthenticationException, IOException, ServletException {
        String username = obtainUsername(request);
        String password = obtainPassword(request);

        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }

        username = username.trim();
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        HttpSession session = request.getSession(false);
        if (session != null || getAllowSessionCreation()) {
            request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username));
        }
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
                         FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) res;
        if (request.getMethod().equals(POST)) {
            // If the incoming request is a POST, then we send it up
            // to the AbstractAuthenticationProcessingFilter.
            super.doFilter(request, response, chain);
        } else {
            // If it's a GET, we ignore this request and send it
            // to the next filter in the chain.  In this case, that
            // pretty much means the request will hit the /login
            // controller which will process the request to show the
            // login page.
            chain.doFilter(request, response);
        }
    }

    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }
}

在进行IT技术方面的修改后,我将在xml中进行以下更改。
 <security:http auto-config="true">
        <!--<session-management session-fixation-protection="none"/>-->
        <security:custom-filter ref="myFilter" before="FORM_LOGIN_FILTER"/>
        <security:intercept-url pattern="/admin/login.jsp*" filters="none"/>
        <security:intercept-url pattern="/admin/report.html" access="ROLE_ADMIN"/>
        <security:form-login login-page="/admin/login.jsp" login-processing-url="/login" always-use-default-target="true"/>
        <security:logout logout-url="/logout" logout-success-url="/login.jsp" invalidate-session="true"/>
    </security:http>   
<security:authentication-manager alias="authenticationManager">
  <security:authentication-provider>
    <security:password-encoder hash="md5" />
    <security:user-service>
    <!-- peter/opal -->
      <security:user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_ADMIN" />
     </security:user-service>
  </security:authentication-provider>
</security:authentication-manager>
<bean id="myFilter" class="com.vanilla.springMVC.controllers.MyFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>

然后我使用JSP编写了我的代码。

<form action="../login" method="post">
    <label for="j_username">Username</label>
    <input type="text" name="j_username" id="j_username" />
    <br/>
    <label for="j_password">Password</label>
    <input type="password" name="j_password" id="j_password"/>
    <br/>
    <input type='checkbox' name='_spring_security_remember_me'/> Remember me on this computer.
    <br/>
    <input type="submit" value="Login"/>
</form>

尝试访问 /admin/report.html 时,我被重定向到登录页面。但是在提交凭据后,我收到以下信息:
HTTP Status 404 - /SpringMVC/login/

type Status report

message /SpringMVC/login/

description The requested resource (/SpringMVC/login/) is not available.

看起来我的配置有问题,但我想不出造成这个问题的原因。你能帮忙吗?


action="../login"? - lschin
没错,../login,因为否则我会得到/admin/login,而我需要父文件夹。 - danny.lesnik
你的应用程序的根目录是/SpringMVC吗?/SpringMVC/login/是正确的/应该可用的吗? - lschin
是的,根目录是/SpringMVC/,然后是安全文件夹/SpringMVC/admin/report.html,接着是登录文件夹/SpringMVC/admin/login.jsp。 - danny.lesnik
我相信我的问题在xml文件中。但是我无法弄清楚问题所在,我有一种感觉是我的过滤器没有起作用,但我不知道如何使它正确运行。 - danny.lesnik
2个回答

11

我大约晚了12个月,但是为了自定义Spring Security表单登录的登录URL,您不需要创建自己的过滤器。form-login标签的一个属性允许您设置自定义URL。实际上,您还可以使用form-login标签的属性更改默认的j_username和j_password字段名称。这里是一个示例:

<form-login login-page="/login" login-processing-url="/login.do" default-target-url="/" always-use-default-target="true" authentication-failure-url="/login?error=1" username-parameter="username" password-parameter="password"/>

0

我认为@Ischin在关注表单操作URL问题方面是正确的。尝试输入完整路径,看看是否有效。如果有效,您可以从那里开始找出是什么不匹配。

我能想到的唯一其他检查项是你的web.xml中的过滤器映射。既然你已经进入了登录页面,你有这个设置,但是我会检查一下你是否只拦截特定扩展名等的URL。

还有,只是提醒一下,如果您希望请求(一旦登录表单验证用户)去到受保护的资源(在这种情况下是/admin/report.html),那么您应该去除form:login always-use-default-target =“true”。将此标志设置为true将导致请求始终转到默认目标URL,通常并非您所需的。来自spring security docs

将其映射到UsernamePasswordAuthenticationFilter的defaultTargetUrl属性。如果未设置,则默认值为“/”(应用程序根目录)。用户在登录后将被带到此URL,前提是他们在尝试访问受保护的资源时没有被要求登录,否则他们将被带到最初请求的URL。

请查看下面的答案,了解有关负投票的更多信息。 - Alessandro Giannone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接