2012-08-22 221 views
1

最近,我开始了一些个人项目,并决定实施Spring Security。我以前曾试图这样做,但那次比我现在没有更好的运气。然后,我解决了这个问题,但是这种方法(直接从代码访问安全上下文并检查它包含的当前用户的角色字符串)感觉就像是一个黑客,我想这次是正确的。Spring安全方法安全注释

现在我有Spring Security大部分功能,据我所知...我可以尝试转到基于角色的重定向页面,它会将我重定向到登录页面。我可以登录信息好的或不正确的信息并发送到正确的位置。我做不到的,我从来没有设法做到的,就是让@Secured或@PreAuthorize注解起作用,就像我希望的那样。

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

我调用了两个由@Secured保护的方法,以及两个分别由@PreAuthorize,一个“ROLE_ADMIN”和一个“ROLE_USER”保护的方法。我登录的帐户只有ROLE_USER权限。在这种情况下,我希望将其重定向到我的accessdenied.jsp页面,并将其设置为我的Spring Security的访问被拒绝页面属性的目标。我不期望的以及我所看到的是,每种方法都在我登录时成功调用并运行。

我有(至少试过)按照教程。我花了几天时间在Google上阅读我能找到的所有内容。我已将我的安全上下文合并到我的上下文中,以及其他一切引起我注意的潜在解决方案。我很抱歉,如果我是一个长期螨,但我宁愿提供太多的信息,而不是太少。为此,下面是我的代码:

的index.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> 

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

的applicationContext。 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> 

感谢您的帮助,您可以提供。

+0

我想直接访问test()方法,它的工作原理。你这样做的方式,它不起作用(即使我有相同的情况)。我怀疑它是否意味着那样。我不确定。所以我已经发布了一个[问题](http://stackoverflow.com/questions/12084480/spring-security-method-level-security-doesnt-work-on-calling-from-another-meth)。 – shazinltc

+0

而我没有看到真正的时间场景,你会真正做到这一点,如果你有一个让我知道。 – shazinltc

+0

这并不是说我有相信会发生这种情况,我只是很难理解为什么安全性会绕过这一点。基本上,我只是试图证明自己的注释是有效的,但我这样做显然是不可能的方式!正如你所说,这显然不是它的工作原理。 –

回答

4

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

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

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

+0

啊,谢谢!我改变了我的代码以使用带有一些受保护方法的自动装配的Test类对象,并且注释似乎按预期运行。我没有意识到Spring Security只会在你尝试从外部类访问方法时才起作用。 –