我正在尝试在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角色,也总是返回我的用户授权。
对我做错了什么的想法?
提前致谢!!
答案 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 注释。