Spring Security 自定义过滤器

发布于 2024-11-06 13:47:30 字数 5462 浏览 1 评论 0原文

我想自定义 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);
    }
}

之后,我在 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.

看起来我的配置有问题,但我无法弄清楚导致此问题的原因。 你能帮忙吗?

I would like to customize Spring security 3.0.5 and change login URL to be /login instead of /j_spring_security_check.

What I need to do, is to to allow login to "/" directory and to secure "/admin/report.html" page.

First of All I create my own filter using tutorial and Spring Security source code:

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);
    }
}

after It I'm making the following changes in 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>

and then I have JSP with my code.

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

when trying to navigate to /admin/report.html I'm redirected to login page.
but after submitting credentials I'm getting:

HTTP Status 404 - /SpringMVC/login/

type Status report

message /SpringMVC/login/

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

It looks like I have problem in configuration, but I can't figure it out what causing this.
Can you help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抹茶夏天i‖ 2024-11-13 13:47:30

我在这方面迟了大约 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"/>

I'm about 12 months late on this one, but in order to customise the login URL of the Spring Security form login you don't need to create your own filter. One of the attributes of the form-login tag allows you to set a custom URL. In fact, you can also change the default j_username and j_password field names using attributes of the form-login tag. Here's an example:

<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"/>
酒绊 2024-11-13 13:47:30

我认为 @Ischin 对表单操作 url 的疑问是正确的。尝试输入完整路径,看看是否有效。如果确实如此,您可以从那里找出不匹配的内容。

我唯一能想到要检查的是 web.xml 中的过滤器映射。由于您正在点击登录页面,因此您已经进行了此设置,但我会检查您是否不仅拦截具有特定扩展名的网址等。

另外,仅供参考,如果您想要请求(一旦登录表单验证了user)转到受保护的资源(在本例中为/admin/report.html),那么您应该删除表单:登录always-use-default-target =“true”。将此标志设置为 true 将导致请求始终转到默认目标 url,这通常不是您想要的。来自 spring 安全文档 :

映射到defaultTargetUrl 属性

用户名密码验证过滤器。
如果不设置,默认值为“/”
(应用程序根目录)。用户将是
登录后转到此 URL,
前提是他们没有被要求登录
当尝试访问安全的
资源,何时将它们带到
最初请求的 URL。

I think that @Ischin is correct to wonder about the form action url. Try putting in the full path and see if that works. If it does, you can work from there to figure out what isn't matching up.

The only other thing I can think of to check is the filter mapping in you web.xml. Since you are hitting the login page you have this set up, but I would check that you're not only intercepting urls with specific extensions, etc.

Also, just as an fyi, if you want the request (once the login form authenticates the user) to go to the secured resource (/admin/report.html in this case) then you should remove the form:login always-use-default-target="true". Setting this flag to true will cause the request to always go to the default target url, which usually isn't what you want. From the spring security docs:

Maps to the defaultTargetUrl property
of
UsernamePasswordAuthenticationFilter.
If not set, the default value is "/"
(the application root). A user will be
taken to this URL after logging in,
provided they were not asked to login
while attempting to access a secured
resource, when they will be taken to
the originally requested URL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文