默认情况下ss3的<x509>标签只会取证书主题作为验证条件,如果想要自己指定证书的某一部分作为验证条件需要手动实现X509PrincipalExtractor接口:
import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor; public class MyX509PrincipalExtractor implements X509PrincipalExtractor{ Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 获取证书序列号 * @param cert x509证书对象 */ @Override public Object extractPrincipal(X509Certificate cert) { String serialNumber = cert.getSerialNumber().toString(16);//取证书序列号作为判断条件 return serialNumber; } }
实现用户描述接口:
public class MyUserAuthority implements UserDetails{ …… }
载入用户信息:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; /** * * Company: xxx公司 <br> * * Description: 用户信息载入服务 * * <br>Copyright: Copyright (c) 2010 - 2015 * * <br>Author: JLCON * <br>Created:2010-9-17 * * <br>Modified:2010-9-17 * * <br>version:V1.0 */ public class MyUserDetailService implements AuthenticationUserDetailsService{ Logger logger = LoggerFactory.getLogger(this.getClass()); //载入用户信息 @Autowired private UserAuthorityInfo userinfo; /** * 用户信息载入 * @param token 认证token */ @Override public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException {//这里得到的就是刚才返回的证书ID return userinfo.getUserDetails(token.getPrincipal().toString()); } }
通过URL获取该URL具有的访问属性:
public class X509securityMetadataSource implements FilterInvocationSecurityMetadataSource{ import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; ………… @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { String url = ((FilterInvocation)object).getRequestUrl(); ……………… return list; } @Override public boolean supports(Class<?> clazz) { return true; } }
认证访问控制器:
public class X509AccessDecisionManager implements AccessDecisionManager{ Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 决定是否有权限访问资源 * @param authentication 登录用户权限信息 * @param object 访问的资源对象 * @param configAttributes 资源对象具有的配置属性 * @exception AccessDeniedException 访问被拒绝 */ @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { FilterInvocation filterInvocation = (FilterInvocation)object; for(ConfigAttribute configAttribute:configAttributes) { for(GrantedAuthority grantedAuthority:authentication.getAuthorities()) { if(configAttribute.getAttribute().equalsIgnoreCase(grantedAuthority.getAuthority())) { logger.debug("访问success! - {}",filterInvocation.getFullRequestUrl()); return; } } } logger.debug("无权访问! - {}",filterInvocation.getFullRequestUrl()); throw new AccessDeniedException("无权限!"); } @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class<?> clazz) { return true; } }
最后上配置:
<?xml version="1.0" encoding="UTF-8"?> <b:beans xmlns:b="http://www.springframework.org/schema/beans" xmlns="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.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> <http access-denied-page="/accessdenied.jsp"> <custom-filter position="X509_FILTER" ref="x509Filter"/> <custom-filter ref="x509Intercepter" before="FILTER_SECURITY_INTERCEPTOR"/> <intercept-url pattern="/*" requires-channel="https"/> <port-mappings> <port-mapping http="8080" https="8443"/> </port-mappings> <form-login/> </http> <b:bean id="preAuthenticatedProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedProcessingFilterEntryPoint"> </b:bean> <b:bean id="x509Filter" class="org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter"> <b:property name="authenticationManager" ref="authenticationmanager"></b:property> <b:property name="principalExtractor"> <b:bean class=".....MyX509PrincipalExtractor"></b:bean> </b:property> </b:bean> <b:bean id="x509Intercepter" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <b:property name="authenticationManager" ref="authenticationmanager"></b:property> <b:property name="securityMetadataSource" ref="x509securityMetadataSource"></b:property> <b:property name="accessDecisionManager" ref="x509AccessDecisionManager"></b:property> </b:bean> <b:bean id="x509securityMetadataSource" class="....X509securityMetadataSource"></b:bean> <b:bean id="x509AccessDecisionManager" class="....X509AccessDecisionManager"></b:bean> <authentication-manager alias="authenticationmanager" > <authentication-provider ref="x509provider"> </authentication-provider> </authentication-manager> <b:bean id="x509provider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider"> <b:property name="preAuthenticatedUserDetailsService" ref="UserDetailsService"> </b:property> <b:property name="throwExceptionWhenTokenRejected" value="true"></b:property> </b:bean> <b:bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener"/> <b:bean id="UserDetailsService" class="....MyUserDetailService"></b:bean> <b:bean id="UserAuthorityInfo" class="....UserAuthorityInfoImp"></b:bean> </b:beans>
web.xml
。。。。。 <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/manager/*</url-pattern> </filter-mapping> 。。。。。
补充UserAuthorityInfo代码:
ABCUserAuthority:
public class ABCUserAuthority implements UserDetails{ private static final long serialVersionUID = -6394802605626145354L; 。。。。。 }
UserAuthorityInfo:
@Repository public class UserAuthorityInfoImp implements UserAuthorityInfo { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SessionFactory sf; public UserDetails getUserDetails(String username) { ABCUserAuthority user = new ABCUserAuthority(); return user; } }