2015-11-03 56 views
0

我想部署一個自定義標記過濾器到我的REST應用程序在春天。我可以在我的數據庫中搜索令牌並驗證它是否存在。當我嘗試驗證用戶的權限時,會出現問題:spring安全始終迴應我,即用戶具有角色。權限驗證不起作用後PRE_AUTH_FILTER

這是我的彈簧security.xml文件

<beans:beans ...> 

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

    <beans:bean id="restServicesEntryPoint" class="org.test.ws.security.RestAuthenticationEntryPoint" /> 
    <beans:bean id="restServicesSuccessHandler" class="org.test.ws.security.RestAuthenticationSuccessHandler" /> 
    <beans:bean id="customAuthenticationProvider" class="org.test.ws.security.CustomAuthenticationProvider" /> 

    <http pattern="/login" security="none" /> 

    <http use-expressions="true" create-session="never" entry-point-ref="restServicesEntryPoint"> 
     <custom-filter ref="restServicesFilter" position="PRE_AUTH_FILTER" /> 
     <intercept-url pattern="/compra" access="ROLE_SUPERVISOR" />   
     <csrf /> 
    </http> 

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

    <beans:bean id="restServicesFilter" class="org.test.ws.security.CustomTokenAuthenticationFilter"> 
     <beans:constructor-arg type="java.lang.String"> 
      <beans:value>/**</beans:value> 
     </beans:constructor-arg> 
     <beans:property name="authenticationManager" ref="authenticationManager" /> 
     <beans:property name="authenticationSuccessHandler" ref="restServicesSuccessHandler" /> 
    </beans:bean> 

這是過濾CustomTokenAuthenticationFilter代碼:

package org.test.ws.security; 

import java.io.IOException; 
import java.text.MessageFormat; 

import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.context.annotation.Bean; 
import org.springframework.security.authentication.AbstractAuthenticationToken; 
import org.springframework.security.authentication.AuthenticationManager; 
import org.springframework.security.authentication.AuthenticationServiceException; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.AuthenticationException; 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; 
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 

public class CustomTokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 
    // private static final Logger logger = LoggerFactory.getLogger(CustomTokenAuthenticationFilter.class); 
    public final String HEADER_SECURITY_TOKEN = "X-CustomToken"; 

    public CustomTokenAuthenticationFilter(String defaultFilterProcessesUrl) { 
     super(defaultFilterProcessesUrl); 
     super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(defaultFilterProcessesUrl)); 
     setAuthenticationSuccessHandler(new RestAuthenticationSuccessHandler()); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, 
     HttpServletResponse response) throws AuthenticationException, IOException, 
       ServletException { 

     String token = request.getHeader(HEADER_SECURITY_TOKEN); 
     AbstractAuthenticationToken userAuthenticationToken = authUserByToken(token); 
     SecurityContextHolder.getContext().setAuthentication(userAuthenticationToken); 

     if (userAuthenticationToken == null) 
      throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token")); 

     return userAuthenticationToken; 
    } 

    @Bean(name = "authenticationManager") 
    @Override 
    public void setAuthenticationManager(AuthenticationManager authenticationManager) { 
     super.setAuthenticationManager(authenticationManager); 
    } 

    private AbstractAuthenticationToken authUserByToken(String token) { 

     if (token == null) { 
      return null; 
     } 

     try { 
      return new AuthenticationToken(token); 
     } catch (Exception e) { 
      // logger.error("Authenticate user by token error: ", e); 
     } 

     return null; 
    } 

    @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("OPTIONS")) { 
      super.doFilter(request, response, chain); 
     } else { 
      chain.doFilter(request, response); 
     } 
    } 
} 

這是CustomAuthenticationProvider代碼:

package org.test.ws.security; 

import org.springframework.security.authentication.AuthenticationProvider; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.AuthenticationException; 
import org.springframework.stereotype.Component; 

@Component 
public class CustomAuthenticationProvider implements AuthenticationProvider { 

    @Override 
    public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
     return authentication; 
    } 

    @Override 
    public boolean supports(Class<?> authentication) { 
     return authentication.equals(AuthenticationToken.class); 
    } 
} 

這是AbstractAuthenticationToken代碼:

package org.test.ws.security; 

import java.util.Collection; 
import java.util.HashSet; 
import java.util.List; 

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import org.springframework.security.authentication.AbstractAuthenticationToken; 
import org.springframework.security.core.GrantedAuthority; 
import org.springframework.security.core.authority.SimpleGrantedAuthority; 

import org.test.dao.implementaciones.UsuarioDaoImpl; 
import org.test.dao.implementaciones.UsuarioRolDaoImpl; 
import org.test.dao.modelos.Usuario; 
import org.test.dao.modelos.UsuarioRol; 

@SuppressWarnings("serial") 
public class AuthenticationToken extends AbstractAuthenticationToken { 
    private ApplicationContext daoContext = new ClassPathXmlApplicationContext("dao-context.xml"); 

    private final Object principal; 
    private Collection<GrantedAuthority> authorities; 

    public AuthenticationToken(String token) throws Exception { 
     super(null); 

     UsuarioDaoImpl usuarioDao = (UsuarioDaoImpl) daoContext.getBean("UsuarioDaoImpl"); 
     Usuario usuario = usuarioDao.check(token); 

     super.setAuthenticated(usuario.getActivo()); 
     super.setDetails(usuario); 
     this.principal = usuario.getUsername(); 
     this.setDetailsAuthorities(); 
    } 

    @Override 
    public Object getCredentials() { 
     return ""; 
    } 

    @Override 
    public Object getPrincipal() { 
     return principal; 
    } 

    @Override 
    public Collection<GrantedAuthority> getAuthorities() { 
     return authorities; 
    } 

    private void setDetailsAuthorities() { 
     UsuarioRolDaoImpl usuarioRolDao = (UsuarioRolDaoImpl) daoContext.getBean("UsuarioRolDaoImpl"); 

     authorities = new HashSet<GrantedAuthority>(); 
     List<UsuarioRol> usuariosRol; 
     try { 
      usuariosRol = usuarioRolDao.list(0, this.principal.toString()); 
      for (UsuarioRol usuarioRol : usuariosRol) { 
       authorities.add(new SimpleGrantedAuthority(usuarioRol.getRol())); 
      } 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

當我運行的代碼,我可以看到這個消息告訴我,比作用在過濾器中創建:

2015-11-03 15:03:13,936 INFO org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser - Creating access control expression attribute 'ROLE_ADMIN' for /compra 

但總是返回我,即使它沒有用戶被授權具有角色ROLE_ADMIN。

任何關於我在做什麼錯的想法?

在此先感謝!

回答

0

最後我可以找到解決方案。

彈簧security.xml文件需要一個的AccessDecisionManager

<beans:beans...> 

    <context:annotation-config /> 
    <context:component-scan base-package="org.test.ws.security" /> 

    <aop:aspectj-autoproxy /> 

    <beans:bean id="restAuthenticationEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" /> 
    <beans:bean id="customAuthenticationProvider" class="org.test.es.security.CustomAuthenticationProvider" /> 

    <http pattern="/login" security="none" /> 

    <http pattern="/**" use-expressions="true" auto-config="true" entry-point-ref="restAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"> 
     <custom-filter ref="restServicesFilter" position="PRE_AUTH_FILTER" /> 
     <access-denied-handler error-page="/auth/access-denied"/> 
    </http> 

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

    <beans:bean id="restServicesFilter" class="org.test.es.security.CustomTokenAuthenticationFilter"> 
     <beans:constructor-arg type="java.lang.String"> 
      <beans:value>/**</beans:value> 
     </beans:constructor-arg> 
     <beans:property name="authenticationManager" ref="authenticationManager" /> 
    </beans:bean> 

    <beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"> 
     <beans:property name="allowIfAllAbstainDecisions" value="true" /> 
     <beans:constructor-arg> 
      <beans:list> 
       <beans:bean class="org.springframework.security.access.vote.RoleVoter" /> 
       <beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" /> 
      </beans:list> 
     </beans:constructor-arg> 
    </beans:bean> 
</beans:beans> 

我不得不添加一個全球方法安全的servlet-context.xml的

<sec:global-method-security pre-post-annotations="enabled" secured-annotations="enabled" proxy-target-class="true" /> 

之後,我可以使用一個@PreAuthorize註釋在我的控制器中。