spring - 在 Spring Security 3 中动态创建新角色和权限

标签 spring spring-security

我在 Struts 2 + Spring IOC 项目中使用 Spring Security 3。

我在我的项目中使用了自定义过滤器、身份验证提供程序等。

你可以在这里看到我的security.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"
  xmlns:p="http://www.springframework.org/schema/p"
   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">


<global-method-security pre-post-annotations="enabled">
        <expression-handler ref="expressionHandler" />
</global-method-security>

<beans:bean id="expressionHandler"
        class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" >
    <beans:property name="permissionEvaluator" ref="customPermissionEvaluator" />
</beans:bean>

<beans:bean class="code.permission.MyCustomPermissionEvaluator" id="customPermissionEvaluator" />

<!-- User Login -->

  <http auto-config="true" use-expressions="true" pattern="/user/*" >
<intercept-url pattern="/index.jsp" access="permitAll"/>
<intercept-url pattern="/user/showLoginPage.action" access="permitAll"/>
<intercept-url pattern="/user/showFirstPage" access="hasRole('ROLE_USER') or hasRole('ROLE_VISIT')"/>
<intercept-url pattern="/user/showSecondUserPage" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/user/showThirdUserPage" access="hasRole('ROLE_VISIT')"/>
<intercept-url pattern="/user/showFirstPage" access="hasRole('ROLE_USER') or hasRole('ROLE_VISIT')"/>
<form-login login-page="/user/showLoginPage.action" />
<logout invalidate-session="true"
        logout-success-url="/"
        logout-url="/user/j_spring_security_logout"/>
<access-denied-handler ref="myAccessDeniedHandler" />

  <custom-filter before="FORM_LOGIN_FILTER" ref="myApplicationFilter"/>
  </http>

    <beans:bean id="myAccessDeniedHandler" class="code.security.MyAccessDeniedHandler" />

    <beans:bean id="myApplicationFilter" class="code.security.MyApplicationFilter">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationFailureHandler" ref="failureHandler"/>
        <beans:property name="authenticationSuccessHandler" ref="successHandler"/>
    </beans:bean>

    <beans:bean id="successHandler"
  class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
      <beans:property name="defaultTargetUrl" value="/user/showFirstPage">   </beans:property>
    </beans:bean>

     <beans:bean id="failureHandler"
  class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
      <beans:property name="defaultFailureUrl" value="/user/showLoginPage.action?login_error=1"/>
    </beans:bean>

    <beans:bean id= "myUserDetailServiceImpl" class="code.security.MyUserDetailServiceImpl">
    </beans:bean>

     <beans:bean id="myAuthenticationProvider" class="code.security.MyAuthenticationProvider">
        <beans:property name="userDetailsService" ref="myUserDetailServiceImpl"/>

    </beans:bean>

 <!-- User Login Ends -->

 <!-- Admin Login -->

    <http auto-config="true" use-expressions="true" pattern="/admin/*" >
    <intercept-url pattern="/index.jsp" access="permitAll"/>
    <intercept-url pattern="/admin/showSecondLogin" access="permitAll"/>
    <intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/>
    <form-login login-page="/admin/showSecondLogin"/>
    <logout invalidate-session="true"
        logout-success-url="/"
        logout-url="/admin/j_spring_security_logout"/>

    <access-denied-handler ref="myAccessDeniedHandlerForAdmin" />
    <custom-filter before="FORM_LOGIN_FILTER" ref="myApplicationFilterForAdmin"/> 
</http>

<beans:bean id="myAccessDeniedHandlerForAdmin" class="code.security.admin.MyAccessDeniedHandlerForAdmin" />

  <beans:bean id="myApplicationFilterForAdmin" class="code.security.admin.MyApplicationFilterForAdmin">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationFailureHandler" ref="failureHandlerForAdmin"/>
        <beans:property name="authenticationSuccessHandler" ref="successHandlerForAdmin"/>
   </beans:bean>

    <beans:bean id="successHandlerForAdmin"
  class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    </beans:bean>

    <beans:bean id="failureHandlerForAdmin"
  class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
       <beans:property name="defaultFailureUrl" value="/admin/showSecondLogin?login_error=1"/>
     </beans:bean>

        <authentication-manager alias="authenticationManager">
    <authentication-provider ref="myAuthenticationProviderForAdmin" />
    <authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>

<beans:bean id="myAuthenticationProviderForAdmin" class="code.security.admin.MyAuthenticationProviderForAdmin">
    <beans:property name="userDetailsService" ref="userDetailsServiceForAdmin"/>
</beans:bean>

<beans:bean id= "userDetailsServiceForAdmin" class="code.security.admin.MyUserDetailsServiceForAdminImpl">
</beans:bean>

 <!-- Admin Login Ends -->

<beans:bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource">
    <beans:property name="basenames">
        <beans:list>
            <beans:value>code/security/SecurityMessages</beans:value>
        </beans:list>
    </beans:property>            
</beans:bean>

到目前为止,您可以看到,我提到的 url-pattern 是硬编码的。我想知道是否有一种方法可以动态创建新的角色和权限,而不是硬编码。

比如创建新的角色和权限并将它们保存到数据库中,然后从数据库中访问。我在网上搜索过,但我无法找到如何在代码中添加新条目。

最佳答案

所以至少有两个问题:

  • 如何使授予的权限/特权/角色动态化?
  • 如何使 URL 的访问限制动态化?

1) 如何使授予的权限/特权/角色动态化?

我不会详细回答这个问题,因为我相信这个主题已经被讨论得足够频繁了。

最简单的方法是将完整的用户信息(登录名、密码和角色)存储在数据库中(3 个表:User、Roles、User2Roles)并使用 JdbcDetailService。您可以在 xml 配置中很好地配置两个 SQL 语句(用于身份验证和授予角色)。

但随后用户需要注销并登录才能获得这些新角色。如果这是 Not Acceptable ,您还必须操纵当前登录用户的角色。它们存储在用户 session 中。我想最简单的方法是在 spring 安全过滤器链中添加一个过滤器,如果需要更改每个请求的角色,它会更新它们。

2) 如何使 URL 的访问限制动态化?

这里有两种方法:

  • 侵入 FilterSecurityInterceptor 并更新 securityMetadataSource,所需的角色应该存储在那里。至少你必须操作方法 DefaultFilterInvocationSecurityMetadataSource#lookupAttributes(String url, String method)
  • 的输出
  • 另一种方法是对 access 属性使用其他表达式,而不是 access="hasRole('ROLE_USER')"。示例:access="isAllowdForUserPages1To3"。当然,您必须创建该方法。这称为“自定义 SpEL 表达式处理程序”(如果您有 Spring Security 3 Book,它在第 210 页左右。希望他们有章节编号!)。所以你现在需要做的就是继承WebSecurityExpressionRoot并引入一个新的方法isAllowdForUserPages1To3。然后你需要继承 DefaultWebSecurityExpressionHandler 并修改 createEvaluationContext 方法,使其第一次请求 StandartEvaluationContext 调用 super (你需要将结果转换为 标准评估上下文)。然后,使用新的 CustomWebSecurityExpressionRoot 实现替换 StandartEvaluationContext 中的 rootObject。这是最难的部分!然后,您需要用新的子类 DefaultWebSecurityExpressionHandler。 (这很糟糕,因为您首先需要显式编写大量安全配置,因为您无法直接从安全命名空间访问它们。)

关于spring - 在 Spring Security 3 中动态创建新角色和权限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8321696/

相关文章:

spring-security - 将 Spring SAML 集成为 SP,将 SimpleSAMLphp 集成为 IdP(HoK 配置文件)

spring - 将字符串转换为本地日期时间

java - Spring + CXF 还是 Spring + Mule?哪一个更好?

spring - ABAC 对 Spring Security 或 Apache Shiro 的支持

java - 如何在 Spring 中处理 DataIntegrityViolationException?

eclipse - 在 Eclipse Luna 中安装 spring 插件

java - 单元测试中通过字段 'userService' 表达的不满足的依赖关系

java - 无法使 CAS 单点注销与 Spring Security 一起使用

Grails Spring 安全/Acegi。自定义用户+密码过期管理

java - 通过 MockMvc 运行时,传递给 ControllerAdvice 的身份验证 token 为空