1

最近,我开始了一个个人项目,我决定实现 Spring Security。我以前曾尝试过这样做,但那时我的运气并不比现在好。然后我解决了这个问题,但是那个方法(直接从代码中访问安全上下文并检查它包含的当前用户的角色字符串)感觉就像一个 hack,我希望这次能做对。

现在,据我所知,我的 Spring Security 大部分都在运行……我可以尝试使用基于角色的重定向转到一个页面,它会将我重定向到登录页面。我可以使用好的或坏的信息登录并被发送到正确的位置。我不能做的,我从来没有做过的,是让@Secured 或@PreAuthorize 注释像我希望的那样运行。

让我试着解释一下(代码将遵循)。我的欢迎/登录页面是 index.jsp,当您登录时,Spring Security 会将您发送到 login.html,这是我在 LoginController 类中映射的方法。在该方法中,我尝试调用大量其他方法:这些方法都不应该是最终的,我只是想向自己证明事情正在运行。

我调用了两种受@Secured 保护的方法,以及两种受@PreAuthorize 保护的方法,一个是“ROLE_ADMIN”,一个是“ROLE_USER”。我登录的帐户只有 ROLE_USER 权限。在这种情况下,我希望根据将其设置为我的 Spring Security 的 access-denied-page 属性的目标来重定向到我的 accessdenied.jsp 页面。我没想到的是,我看到的是,当我登录时,每个方法都被成功调用并运行。

我已经(至少尝试过)遵循教程。我在谷歌上花了几天时间,阅读我能找到的所有东西。我已将我的安全上下文合并到我的上下文中,以及作为潜在解决方案引起我注意的所有其他内容。如果我啰嗦了,我很抱歉,但我宁愿提供太多信息而不是太少。为此,以下是我的代码:

索引.jsp

    <html>
    <body>
        <form action="j_spring_security_check" method="POST">
            <label for="j_username">Name:</label> 
            <input id="j_username" type='text' name='j_username' /> 
            <br /> 
            <label for="j_password" class="passwordField">Password:</label> 
            <input id="j_password" type='password' name='j_password' /> 
            <br />
            <input id="proceed" type="submit" value="Submit" />
        </form>
    </body>
    </html>

登录控制器.java

package cribbage.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import org.springframework.jdbc.core.JdbcTemplate;

import cribbage.database.entity.Test;

@Controller
public class LoginController {
    @Autowired
    JdbcTemplate t;

    @RequestMapping(value = "/login")
    public ModelAndView login(HttpServletRequest request) {
        test();
        test2();
        test3();
        test4();
        return new ModelAndView("test.jsp");
    }

    @Secured("ROLE_ADMIN")
    public void test(){
        System.out.println("Test One");
    }

    @Secured("ROLE_USER")
    public void test2(){
        System.out.println("Test Two");
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public void test3(){
        System.out.println("Test Three");
    }

    @PreAuthorize("hasRole('ROLE_USER')")
    public void test4(){
        System.out.println("Test Four");
    }
}

web.xml

<web-app version="2.5" 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_2_5.xsd">

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<display-name>Spring Security Tutorial Application</display-name>

<!-- - Location of the XML file that defines the root application context 
    - Applied by ContextLoaderListener. -->

<context-param>
    <description>Spring context file</description>
    <param-name>contextConfigLocation</param-name>
    <param-value>
       /WEB-INF/applicationContext.xml
       /WEB-INF/applicationContext-security.xml
   </param-value>
</context-param>

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

<!-- - Provides core MVC application controller. See bank-servlet.xml. -->
<servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
            /WEB-INF/applicationContext-security.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

应用程序上下文.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd            
                    http://www.springframework.org/schema/tx
                    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd         
                    http://www.springframework.org/schema/context 
                    http://www.springframework.org/schema/context/spring-context-3.1.xsd            
                    http://www.springframework.org/schema/aop 
                    http://www.springframework.org/schema/aop/spring-aop.xsd
                    http://www.springframework.org/schema/mvc
                    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
                    http://www.springframework.org/schema/security 
                    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

<context:property-placeholder location="classpath:*.properties" />

<mvc:annotation-driven />

<!-- Which packages to scan when looking for beans defined with @Component -->
<context:component-scan scoped-proxy="targetClass"
    base-package="cribbage.controller
                  cribbage.database.dao
                  cribbage.database.entity" />
<context:annotation-config />

<!-- Turn on AspectJ @Configurable support -->

<!-- Turn on @Autowired, @PostConstruct etc support -->
<bean
    class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean
    class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

<!-- Add Transaction support -->
<!-- Use @Transaction annotations for managing transactions -->
<tx:annotation-driven transaction-manager="txManager" />

<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource" />

<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.SessionLocaleResolver"
    p:defaultLocale="en_US" />

<!-- For database, uses maven filtering to fill in place holders -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="${db.driver}" />
    <property name="url" value="${db.url}" />
    <property name="username" value="${db.username}" />
    <property name="password" value="${db.password}" />
    <property name="maxActive" value="10" />
    <property name="maxIdle" value="1" />
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <constructor-arg ref="dataSource" />
</bean>

<security:global-method-security
    secured-annotations="enabled" pre-post-annotations="enabled" />

applicationContext-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/security 
                http://www.springframework.org/schema/security/spring-security-3.1.xsd">

<http pattern="/CSS/**" security="none" />

<http auto-config="true" use-expressions="true" access-denied-page="/accessdenied.jsp">
    <form-login always-use-default-target="false"
        login-processing-url="/j_spring_security_check" default-target-url="/login.html"
        login-page="/index.jsp" authentication-failure-url="/loginFailed.jsp" />
    <logout logout-url="/j_spring_security_logout" />
    <intercept-url pattern="/test.jsp" access="hasRole('ROLE_USER')" />
</http>

<authentication-manager>
    <authentication-provider>
        <jdbc-user-service data-source-ref="dataSource"
            users-by-username-query="select username,user_password,enabled from users where username=?"
            authorities-by-username-query="select username,authority,enabled from users where username=?" />
    </authentication-provider>
</authentication-manager>

感谢您提供的任何帮助。

4

1 回答 1

4

实际上,spring security 仅在涉及方面/安全拦截器时才有效。在您的代码中 test(),test2(),test3(),test4() 直接从控制器方法登录调用。所以不会有任何方面的参与导致安全被绕过。

如果测试方法是另一个 spring bean 的一部分,那么这应该像你所期望的那样工作。

或者如果它们在同一个类中,则应该使用 spring bean 而不是 this(当前对象)调用它。

于 2012-08-23T04:21:10.153 回答