在PRE_AUTH_FILTER之后,权限验证不起作用

时间:2015-11-03 14:05:30

标签: spring spring-security

我正在尝试在Spring中将自定义令牌过滤器部署到我的REST应用程序。我可以在我的数据库中搜索令牌,如果它存在则验证。当我尝试验证用户的权限时会出现问题:spring security始终响应我,即用户具有角色。

这是我的spring-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角色,也总是返回我的用户授权。

对我做错了什么的想法?

提前致谢!!

1 个答案:

答案 0 :(得分:0)

最后我找到了解决方案。

我的 spring-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 中添加 global-method-security

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

之后,我可以在控制器中使用 @PreAuthorize 注释。