0

我有一个使用 Spring Security (3.1) 的 webapp,并且我有 3 个不同的角色(ROLE_ADMIN、ROLE_CONS、ROLE_S_CEN)

当我使用具有 ROLE_ADMIN 角色的用户登录时,一切都按预期工作,但是当我使用具有 ROLE_CONS 角色的另一个用户登录时,它就不起作用了......

这是我的 security-context.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       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.1.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

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

   <security:http auto-config="false" use-expressions="true" entry-point-ref="http403EntryPoint" access-denied-page="/autenticacion/accesodenegado">
        <security:intercept-url pattern="/" access="permitAll"/>
        <security:intercept-url pattern="/403.jsp" access="permitAll"/>
        <!-- Allow non-secure access to static resources  -->
        <security:intercept-url pattern="/resources/**" access="permitAll"/>
        <security:intercept-url pattern="/autenticacion/**" access="permitAll"/>
        <!-- URLs que dependen de perfiles -->
        <security:intercept-url pattern="/gestion/facturas/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN','ROLE_CONS')"/>
        <security:intercept-url pattern="/gestion/tarifas/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN','ROLE_CONS')"/>
        <security:intercept-url pattern="/gestion/envios/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN')"/>
        <security:intercept-url pattern="/gestion/perfiles/**" access="hasRole('ROLE_ADMIN')"/>
        <security:intercept-url pattern="/gestion/usuarios/**" access="hasRole('ROLE_ADMIN')"/>
        <security:intercept-url pattern="/consulta/**" access="hasAnyRole('ROLE_CONS','ROLE_ADMIN','ROLE_S_CEN')"/>
        <security:intercept-url pattern="/importacion/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN')"/>
        <!-- Pantalla a la que redirige el logout -->           
        <security:logout logout-success-url="/"/>
    </security:http>

    <bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint">
    </bean>

    <bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
        <security:filter-chain-map path-type="ant">
            <security:filter-chain pattern="/**" filters="j2eePreAuthFilter"/>
        </security:filter-chain-map>
    </bean>


    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref='preAuthenticatedAuthenticationProvider'/>
    </security:authentication-manager>

    <bean id="preAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService" ref="preAuthenticatedUserDetailsService"/>
    </bean>

    <bean id="preAuthenticatedUserDetailsService"
            class="org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService"/>


    <bean id="j2eePreAuthFilter" class="es.myapp.security.MyAppUserJ2eePreAuthenticatedProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationDetailsSource" ref="authenticationDetailsSource"/>
        <property name="continueFilterChainOnUnsuccessfulAuthentication" value="false"/>
    </bean>

  <bean id="authenticationDetailsSource" class="org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource">
    <property name="mappableRolesRetriever" ref="j2eeMappableRolesRetriever"/>
    <property name="userRoles2GrantedAuthoritiesMapper" ref="j2eeUserRoles2GrantedAuthoritiesMapper"/>
  </bean>

  <bean id="j2eeMappableRolesRetriever" class="org.springframework.security.web.authentication.preauth.j2ee.WebXmlMappableAttributesRetriever">
  </bean>

   <bean id="j2eeUserRoles2GrantedAuthoritiesMapper" class="org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper">
    <property name="attributePrefix" value="test"/>
  </bean>


</beans>

还有我的 menu.jsp

<%@ taglib uri="http://www.springframework.org/tags" prefix="s"%>
<%@ taglib uri="/WEB-INF/security.tld"  prefix="sec"%>
<div class="inner"> 
    <sec:authorize access="isAuthenticated()">
        <ul id="menu">
            <li>
                <a href="#"><span id="padre" class="abierto"><s:message code="menu.conexion.capri"/></span></a>
                <div class="sub_menu">
                    <ul>
                        <sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN')">
                            <li>
                                <a href="<s:url value="/importacion/datos"/>"><span><s:message code="menu.importacion.importarDatos"/></span></a>
                            </li>
                        </sec:authorize>
                        <sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN')">
                            <li>
                                <a href="<s:url value="/gestion/envios"/>"><span><s:message code="menu.gestion.envios"/></span></a>
                            </li>
                        </sec:authorize>
                        <sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN','ROLE_CONS')">
                            <li>
                                <a href="<s:url value="/consulta/envios"/>"><span><s:message code="menu.consulta.envios"/></span></a>
                            </li>
                        </sec:authorize>
                        <sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN')">                  
                            <li>
                                    <a href="<s:url value="/gestion/facturas"/>"><span><s:message code="menu.gestion.facturas"/></span></a>
                            </li>
                        </sec:authorize>
                        <sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN','ROLE_CONS')">                  
                            <li>
                                <a href="<s:url value="/gestion/tarifas"/>"><span><s:message code="menu.gestion.tarifas"/></span></a>
                            </li>
                        </sec:authorize>

                            <li>
                                <a href="<s:url value="/gestion/envios/verpaginarecibir"/>"><span><s:message code="menu.recibir.envios"/></span></a>
                            </li>

                    </ul>
                </div>
            </li>
            <sec:authorize access="hasRole('ROLE_ADMIN')">
                <li>
                    <a href="#"><span id="padre" class="abierto"><s:message code="menu.usuarios"/></span></a>
                    <div class="sub_menu">
                        <ul>            
                            <sec:authorize access="hasRole('ROLE_ADMIN')">                  
                                <li>
                                    <a href="<s:url value="/gestion/usuarios"/>"><span><s:message code="menu.gestion.usuarios"/></span></a>
                                </li>
                            </sec:authorize>
                            <sec:authorize access="hasRole('ROLE_ADMIN')">                      
                                <li>
                                    <a href="<s:url value="/gestion/perfiles"/>"><span><s:message code="menu.gestion.perfiles"/></span></a>
                                </li>                   
                            </sec:authorize>    
                        </ul>
                    </div>                          
                </li>       
            </sec:authorize>
        </ul>   
    </sec:authorize>
</div>

当我使用具有 ROLE_CONS 角色的用户登录时,我只被允许查看没有安全性的页面和 url,但不允许 ROLE_CONS 看到那些 ROLE_CONS ......

我已经检查过用户是否经过了正确的身份验证,并且它具有 ROLE_CONS 作为权限...

有任何想法吗?

编辑添加了当我使用 ROLE_CONS 登录时由 menu.jsp 生成的 HTML:

<ul id="menu">
  <li>
    <a href="#"><span id="padre" class="abierto">Conexión CAPRI</span></a>
    <div class="sub_menu">
      <ul>
    <li>
      <a href="/myApp/gestion/envios/verpaginarecibir"><span>Recibir envíos</span></a>
    </li>
      </ul>
    </div>
  </li>
</ul>

这是我登录时的调试输出:

INFO : Spring Security Debugger - 

************************************************************

Request received for '/autenticacion/inicio?lang=es':

org.apache.catalina.connector.RequestFacade@5b34329b

servletPath:/autenticacion/inicio
pathInfo:null

Security filter chain: [
  SecurityContextPersistenceFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]


************************************************************


DEBUG: es.myApp.security.MyAppUserJ2eePreAuthenticatedProcessingFilter - Checking secure context token: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@bf1d7451: Principal: org.springframework.security.core.userdetails.User@27a6eeec: Username: centro1; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_CONS ; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_CONS 
DEBUG: es.myApp.controller.MyAppDispatcherServlet - DispatcherServlet with name 'Spring MVC Dispatcher Servlet' processing GET request for [/myApp/autenticacion/inicio]
DEBUG: es.myApp.controller.MyAppDispatcherServlet - Last-Modified value for [/myApp/autenticacion/inicio] is: -1
DEBUG: es.myApp.controller.MyAppDispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'inicio'; URL [/WEB-INF/jsp/inicio.jsp]] in DispatcherServlet with name 'Spring MVC Dispatcher Servlet'
DEBUG: es.myApp.controller.MyAppDispatcherServlet - Successfully completed request

这是 MyAppUserJ2eePreAuthenticatedProcessingFilter

package es.myApp.security;

import java.util.ArrayList;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import es.myApp.Constantes;
import es.myApp.modelo.datos.dominio.usuario.Perfil;
import es.myApp.security.impl.MyAppGrantedAuthorityImpl;

public class MyAppUserJ2eePreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {   
        MyAppUser usuario = (MyAppUser)request.getSession().getAttribute(Constantes.USUARIO_SESION);
        return usuario.getCredentials();
    }

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        MyAppUser user = (MyAppUser)request.getSession().getAttribute(Constantes.USUARIO_SESION);
        if (user.getLogin() != null) {
            Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
            for (Perfil p: user.getPerfiles()) {
                authorities.add(new MyAppGrantedAuthorityImpl(p.getCodPerfil()));
            }
        }
        return user;
    }

}

这是 MyAppGrantedAuthorityImpl

package es.myappsecurity.impl;

import es.myappsecurity.MyAppGrantedAuthority;

@SuppressWarnings("serial")
public class MyAppGrantedAuthorityImpl implements MyAppGrantedAuthority {

    private String autority;

    public MyAppGrantedAuthorityImpl(String autority) {
        super();
        this.autority = autority;
    }

    public void setAutority(String autority) {
        this.autority = autority;
    }

    @Override
    public String getAuthority() {
        return this.autority;
    }

    @Override
    public String toString() {
        return this.autority;
    }

}
4

2 回答 2

1

这应该可行,因此我将尝试找到这种情况的潜在问题根源:

  1. 您为 sec taglib 使用自定义 URI:<%@ taglib uri="/WEB-INF/security.tld" prefix="sec"%>- 为什么不使用标准 URI?你使用 Maven 吗?

  2. 你能显示MyAppUserJ2eePreAuthenticatedProcessingFilter代码吗?

  3. 您同时使用<security:http>namespace config <bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">,这可能是潜在的问题。尝试在里面添加这个<http>

    <sec:custom-filter ref="j2eePreAuthFilter" position="PRE_AUTH_FILTER" />
    

    顺便说一句,在 Spring Security 3.1 中,您可以创建多个<http>元素

编辑:

我知道问题出在哪里......是否es.myApp.modelo.datos.dominio.security.impl.MyAppGrantedAuthorityImpl正确实施了equals和hashCode?你能显示源代码吗?

您可以执行extend SimpleGrantedAuthority implements MyAppGrantedAuthority或尝试此实现:

public class MyAppGrantedAuthorityImpl implements MyAppGrantedAuthority {

    private String autority;

    public MyAppGrantedAuthorityImpl(String autority) {
        super();
        if (autority == null || autority.isEmpty()) {
            throw new IllegalArgumentException("Authority cannot be empty");
        }
        this.autority = autority;
    }

    public void setAutority(String autority) {
        this.autority = autority;
    }

    @Override
    public String getAuthority() {
        return this.autority;
    }

    @Override
    public String toString() {
        return this.autority;
    }

    public boolean equals(Object obj) {
        if (obj instanceof String) {
            return obj.equals(this.autority);
        }

        if (obj instanceof GrantedAuthority) {
            GrantedAuthority attr = (GrantedAuthority) obj;

            return this.autority.equals(attr.getAuthority());
        }

        return false;
    }

    public int hashCode() {
        return this.autority.hashCode();
    }

}
于 2012-09-11T10:28:22.853 回答
0

好吧,这真的很奇怪...如果我将角色名称从 ROLE_CONS 更改为 ROLE_CONSL 它可以工作...我认为这是因为数据库中的字段长度为 10 个字符...我没有找到其他解释... O_o

所有工作的角色都是 10 个字符长(ROLE_ADMIN 和 ROLE_S_CEN).. 失败的角色是 9 个字符......

无论如何,这很奇怪,因为当我在 jsp 中打印角色名称时,它是 9 个字符而不是 'ROLE_CONS' 或任何东西......

于 2012-09-11T11:37:50.513 回答