CAS单点登录和spring securtiy集成
说明:本文章主要建立在spring-security早已集成在系统中的前提下:
1.需要创建一个spring-security.xml文件并关联在applicationContext.xml文件中:<import resource="spring-security.xml" />
2.在web.xml文件中配置单点登录监听:
<!--单点登录登录登出监听器-->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- spring securtiy 过滤器配置 -->
<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>/*</url-pattern>
</filter-mapping>
3.下面把spring-security.xml的内容贴出来:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/p
http://www.springframework.org/schema/context/spring-p-3.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<beans:description>SpringSecurity</beans:description>
<beans:bean id="customWebInvocationPrivilegeEvaluator"
class="org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator">
<beans:constructor-arg ref="baseFilter" />
</beans:bean>
<http pattern="/index.jsp" security="none" />
<http pattern="/**/*.css" security="none" />
<http pattern="/**/*.ico" security="none" />
<http pattern="/**/*.js" security="none" />
<http pattern="/**/*.jpg" security="none" />
<http pattern="/**/*.png" security="none" />
<http pattern="/**/*.gif" security="none" />
<http pattern="/**/*.pdf" security="none" />
<http pattern="/**/*.xls" security="none" />
<http pattern="/**/*.xml" security="none" />
<http pattern="/**/*.html" security="none" />
<http pattern="/bsp/routePush" security="none" />
<http pattern="/base/common/forbiddenDialog.jsp" security="none" />
<http pattern="/**/index.html" security="none" />
<http pattern="/**/ws/**" security="none" />
<http pattern="/base/print/print/install_lodop32.exe" security="none" />
<http pattern="/base/print/print/install_lodop64.exe" security="none" />
<http pattern="/index/login" security="none" />
<http pattern="/orderAlcsProcess" security="none" />
<http pattern="/customerProcess" security="none" />
<http pattern="/remote/**" security="none" />
<http pattern="/notice/findAllNotice" security="none" />
<http pattern="/notice/findNoticeById" security="none" />
<http pattern="/dwr/**" security="none" />
<http pattern="/base/common/image.jsp" security="none" />
<http pattern="/randCode/takeRand" security="none" />
<!-- http安全配置 -->
<http auto-config="true" entry-point-ref="casEntryPoint"
use-expressions="true" servlet-api-provision="true">
<intercept-url pattern="/**/*" access="isAuthenticated()" />
<!-- 尝试访问没有权限的页面时跳转的页面 -->
<access-denied-handler error-page="/index.jsp" />
<!-- authentication-success-handler-ref 成功之后处理类 -->
<form-login login-page="/base/login.jsp"
default-target-url="/base/login.jsp"
authentication-failure-url="${cas.logoutUrl}"
authentication-success-handler-ref="baseSuccessHandler" />
<logout invalidate-session="true" logout-success-url="${cas.logoutUrl}" />
<session-management session-fixation-protection="none">
<concurrency-control />
</session-management>
<!-- 增加一个filter,这点与Acegi是不一样的,不能修改默认的filter了,这个filter位于FILTER_SECURITY_INTERCEPTOR之前 -->
<custom-filter ref="casFilter" position="CAS_FILTER" />
<custom-filter ref="baseFilter" before="FILTER_SECURITY_INTERCEPTOR" />
</http>
<beans:bean id="baseFilter"
class="com.sf.oms.security.spring.BaseFilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManagerBean" />
<beans:property name="securityMetadataSource" ref="securityMetadataSource" />
</beans:bean>
<!-- 用户的密码加密或解密 -->
<beans:bean id="passwordEncoder"
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder">
</beans:bean>
<!-- 项目实现的用户查询服务,将用户信息查询出来 -->
<beans:bean id="userDetailsService"
class="com.sf.oms.security.spring.BaseUserDetailsServiceImpl">
<beans:property name="messageSource" ref="messageSource"></beans:property>
<beans:property name="userService" ref="userService"></beans:property>
<beans:property name="tmDepartmentMqService" ref="departmentMqService"></beans:property>
</beans:bean>
<!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
<beans:bean id="accessDecisionManagerBean"
class="com.sf.oms.security.spring.BaseAccessDecisionManager"></beans:bean>
<!-- 资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 -->
<beans:bean id="securityMetadataSource"
class="com.sf.oms.security.spring.FilterInvocationSecurityMetadataSourceImpl">
<beans:constructor-arg index="0" ref="roleService" />
<beans:constructor-arg index="1" ref="resourceService" />
</beans:bean>
<!-- 定义国际化 -->
<beans:bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<beans:property name="basename" value="classpath:message_zh_CN" />
</beans:bean>
<!-- 成功之后处理类 该类继承springsecurity 成功后的处理类 处理一些自己的操作后再交给 springsecurity成功后的处理类
跳转 -->
<beans:bean id="baseSuccessHandler"
class="com.sf.oms.security.spring.BaseAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/base/index.jsp"></beans:property>
<beans:property name="alwaysUseDefaultTargetUrl" value="false"></beans:property>
<beans:property name="loginLogService" ref="loginLogService"></beans:property>
</beans:bean>
<!-- cas中心认证服务入口 -->
<beans:bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<beans:property name="loginUrl"
value="${cas.loginUrl}" />
<beans:property name="serviceProperties" ref="serviceProperties" />
</beans:bean>
<!-- cas中心认证服务配置,登录成功后的返回地址 -->
<beans:bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<beans:property name="service"
value="${cas.service}" />
<beans:property name="sendRenew" value="false" />
</beans:bean>
<!-- CAS service ticket(中心认证服务凭据)验证 -->
<beans:bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler"
ref="authenticationSuccessHandler" />
<beans:property name="authenticationFailureHandler"
ref="authenticationFailureHandler" />
</beans:bean>
<!-- 登录成功处理器 -->
<beans:bean id="authenticationSuccessHandler"
class="com.sf.oms.security.spring.BaseAuthenticationSuccessHandler">
<beans:property name="alwaysUseDefaultTargetUrl" value="true"></beans:property>
<beans:property name="defaultTargetUrl" value="/base/index.jsp"></beans:property>
</beans:bean>
<!-- 登录失败 -->
<beans:bean id="authenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl"
value="${cas.logoutUrl}"></beans:property>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>
<beans:bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<beans:property name="authenticationUserDetailsService"
ref="casAuthenticationUserDetailsService" />
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="ticketValidator">
<beans:bean
class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<beans:constructor-arg index="0"
value="${cas.ServerUrlPrefix}" />
</beans:bean>
</beans:property>
<beans:property name="key"
value="an_id_for_this_auth_provider_only" />
</beans:bean>
<beans:bean id="casAuthenticationUserDetailsService"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<beans:property name="userDetailsService">
<beans:ref bean="userDetailsService" />
</beans:property>
</beans:bean>
<!--客户端注销 -->
<beans:bean id="singleLogoutFilter"
class="org.jasig.cas.client.session.SingleSignOutFilter" />
</beans:beans>
4.重写配置中用到的拦截器 BaseFilterSecurityInterceptor
/**
*
* BaseFilterSecurityInterceptor.java
*
*/
package com.sf.oms.security.spring;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
/**
* The Class BaseFilterSecurityInterceptor.
*/
public class BaseFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
/** The security metadata source. */
private FilterInvocationSecurityMetadataSource securityMetadataSource;
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
/**
* Gets the security metadata source.
*
* @author 596570
* @date 2014-12-8 20:41:01
* @since
* @return the security metadata source
*/
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}
/* (non-Javadoc)
* @see org.springframework.security.access.intercept.AbstractSecurityInterceptor#getSecureObjectClass()
*/
public Class<? extends Object> getSecureObjectClass() {
return FilterInvocation.class;
}
/**
* Invoke.
*
* @author 596570
* @date 2014-12-8 20:41:01
* @since
* @param fi the fi
* @throws IOException Signals that an I/O exception has occurred.
* @throws ServletException the servlet exception
*/
public void invoke(FilterInvocation fi) throws IOException,ServletException {
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}finally {
super.afterInvocation(token, null);
}
}
/* (non-Javadoc)
* @see org.springframework.security.access.intercept.AbstractSecurityInterceptor#obtainSecurityMetadataSource()
*/
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
/**
* Sets the security metadata source.
*
* @author 596570
* @date 2014-12-8 20:41:01
* @since
* @param securityMetadataSource the new security metadata source
*/
public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
this.securityMetadataSource = securityMetadataSource;
}
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig filterconfig) throws ServletException {
// TODO Auto-generated method stub
}
}
5.BaseUserDetailsServiceImpl
/**
*
* BaseUserDetailsServiceImpl.java
*
*/
package com.sf.oms.security.spring;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.dao.DataAccessException;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import com.sf.oms.common.base.BaseUserDetail;
import com.sf.oms.mq.dto.TmDepartmentMq;
import com.sf.oms.mq.service.TmDepartmentMqService;
import com.sf.oms.security.user.dto.BaseUser;
import com.sf.oms.security.user.dto.BaseUserRole;
import com.sf.oms.security.user.service.UserService;
import com.sf.oms.utils.Constants;
/**
* The Class BaseUserDetailsServiceImpl.
*/
@SuppressWarnings({ "unused" })
public class BaseUserDetailsServiceImpl implements UserDetailsService,UserDetailsContextMapper {
/** The Constant logger. */
private static final Logger LOGGER = LoggerFactory
.getLogger(BaseUserDetailsServiceImpl.class);
/** The messages. */
protected MessageSourceAccessor messages;
/** The user service. */
private UserService userService;
/** The org service. */
private TmDepartmentMqService tmDepartmentMqService;
/* (non-Javadoc)
* @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
*/
public UserDetails loadUserByUsername(String userAccount)
throws UsernameNotFoundException, DataAccessException {
Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
BaseUser baseUser = userService.findUserByUserName(userAccount);
if (null == baseUser) {
LOGGER.info("用户名:{}不存在", userAccount);
throw new UsernameNotFoundException(
messages.getMessage("BaseUserDetailServiceImpl.notExistUser"));
}
try {
//根据用户查找它所拥有的资源
List<BaseUserRole> list = userService.findRoleByUserId(baseUser
.getId());
// 去重
Set<String> l = new HashSet<String>();
for (BaseUserRole userRole : list) {
l.add(userRole.getRoleId());
}
List<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
SimpleGrantedAuthority sga = null;
boolean isAdminRole = false;
if (CollectionUtils.isNotEmpty(list)) {
for (BaseUserRole userRole : list) {
if(Constants.ADMIN_ROLE_ID.equals(userRole.getRoleId())){
isAdminRole = true;
}
sga = new SimpleGrantedAuthority(userRole.getRoleId());
auth.add(sga);
}
}
//根据用户所属区部查找经营本部
TmDepartmentMq headerOrg = this.tmDepartmentMqService.findHeaderByAreaCode(baseUser.getRostralCode());
String headerAreaCode = null;
String headerAreaName = null;
if(headerOrg != null){
headerAreaCode = headerOrg.getDeptCode();
headerAreaName = headerOrg.getDeptName();
}
// 取得用户的密码
String password = baseUser.getPassword();
boolean isValidity = 1 == baseUser.getIsValidity() ? true : false;
BaseUserDetail user = new BaseUserDetail(baseUser.getId(), userAccount, baseUser.getUserName(),
baseUser.getPassword(), baseUser.getUserCode(), baseUser.getDeptCode(), null,
baseUser.getRostralCode(), baseUser.getRostralName(), headerAreaCode, headerAreaName, true,isAdminRole, true,
true,l, isValidity, auth);
return user;
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw new UsernameNotFoundException("系统错误");
}
}
/**
* Sets the message source.
*/
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
/**
* Sets the user service.
*/
public void setUserService(UserService userService) {
this.userService = userService;
}
/**
* @param tmDepartmentMqService the tmDepartmentMqService to set
*/
public void setTmDepartmentMqService(TmDepartmentMqService tmDepartmentMqService) {
this.tmDepartmentMqService = tmDepartmentMqService;
}
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx,
String username, Collection<? extends GrantedAuthority> authorities) {
return this.loadUserByUsername(username);
}
@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
// TODO Auto-generated method stub
}
}
5.BaseAccessDecisionManager
/**
*
* BaseAccessDecisionManager.java
*
*/
package com.sf.oms.security.spring;
import java.util.Collection;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
/**
* The Class BaseAccessDecisionManager.
*/
public class BaseAccessDecisionManager implements AccessDecisionManager {
/** The Constant logger. */
private static final Logger LOGGER = LoggerFactory.getLogger(BaseAccessDecisionManager.class);
//In this method, need to compare authentication with configAttributes.
// 1, A object is a URL, a filter was find permission configuration by this URL, and pass to here.
// 2, Check authentication has attribute in permission configuration (configAttributes)
// 3, If not match corresponding authentication, throw a AccessDeniedException.
/* (non-Javadoc)
* @see org.springframework.security.access.AccessDecisionManager#decide(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)
*/
public void decide(Authentication authentication, Object object,Collection<ConfigAttribute> configAttributes)throws AccessDeniedException, InsufficientAuthenticationException {
if(configAttributes == null){
return ;
}
Iterator<ConfigAttribute> ite=configAttributes.iterator();
while(ite.hasNext()){
ConfigAttribute ca=ite.next();
String needAuthority=((SecurityConfig)ca).getAttribute();
for(GrantedAuthority ga:authentication.getAuthorities()){
if(needAuthority.equals(ga.getAuthority())){
return;
}
}
}
if(authentication.getPrincipal() instanceof UserDetails){
UserDetails userDetails = (UserDetails)authentication.getPrincipal();
LOGGER.info( userDetails.getUsername() + " access " + object);
}
LOGGER.info(authentication + "访问无权限的" + object);
throw new AccessDeniedException("no right");
}
/* (non-Javadoc)
* @see org.springframework.security.access.AccessDecisionManager#supports(org.springframework.security.access.ConfigAttribute)
*/
public boolean supports(ConfigAttribute attribute) {
return true;
}
/* (non-Javadoc)
* @see org.springframework.security.access.AccessDecisionManager#supports(java.lang.Class)
*/
public boolean supports(Class<?> clazz) {
return true;
}
}
6.FilterInvocationSecurityMetadataSourceImpl
/**
*
* FilterInvocationSecurityMetadataSourceImpl.java
*
*/
package com.sf.oms.security.spring;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import com.sf.oms.cache.base.CacheUtil;
import com.sf.oms.cache.buscache.base.CacheConstant;
import com.sf.oms.security.resource.dto.BaseResource;
import com.sf.oms.security.resource.service.ResourceService;
import com.sf.oms.security.role.dto.BaseRoleResource;
import com.sf.oms.security.role.service.RoleService;
/**
* The Class FilterInvocationSecurityMetadataSourceImpl.
*/
public class FilterInvocationSecurityMetadataSourceImpl implements
FilterInvocationSecurityMetadataSource {
/** The role service. */
private RoleService roleService;
/** The resource service. */
private ResourceService resourceService;
/** The Constant logger. */
private static final Logger LOGGER = LoggerFactory
.getLogger(FilterInvocationSecurityMetadataSourceImpl.class);
/**
* Instantiates a new filter invocation security metadata source impl.
*
* @param roleService
* the role service
* @param resourceService
* the resource service
*/
public FilterInvocationSecurityMetadataSourceImpl(RoleService roleService,
ResourceService resourceService) {
this.resourceService = resourceService;
this.roleService = roleService;
}
/**
* Gets the resource map.
*/
private Map<String, Collection<ConfigAttribute>> getResourceMap() {
Map<String, Collection<ConfigAttribute>> resourceMap = null;
try {
//先从缓存中查找是否有资源,如果没有就从数据库加载,并放入缓存
resourceMap = CacheUtil.getMap(CacheConstant.OMS_RESOURCE_MAP);
if (null == resourceMap) {
resourceMap = loadResourceDefine();
CacheUtil.setMapAll(CacheConstant.OMS_RESOURCE_MAP, resourceMap);
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
return resourceMap;
}
/**
* Load resource define.
*/
private Map<String, Collection<ConfigAttribute>> loadResourceDefine() {
//定义SpringSecurity的权限集合
Map<String, Collection<ConfigAttribute>> resourceMaps = new HashMap<String, Collection<ConfigAttribute>>();
//查询所有的角色与资源的关系
List<BaseRoleResource> roleResourceList = roleService.findAllRoleResource();
//查询所有的资源
List<BaseResource> baseResourceList = resourceService.findAllResource();
Collection<ConfigAttribute> atts = null;
//找到角色与资源的对应有关系
for (BaseResource baseResource : baseResourceList) {
// 查找resourceCode对应的roleCode
List<String> roleCodeList = searchRole(baseResource.getId(),
roleResourceList);
ConfigAttribute ca = null;
String url = baseResource.getResourceUrl();
if (StringUtils.isEmpty(url)) {
continue;
}
String[] urls = url.split(",");
for (String key : urls) {
key = getTrueUrl(key);
if (resourceMaps.containsKey(key)) {
atts = resourceMaps.get(key);
} else {
atts = new ArrayList<ConfigAttribute>();
}
for (String string : roleCodeList) {
ca = new SecurityConfig(string);
atts.add(ca);
}
resourceMaps.put(key, atts);
}
}
return resourceMaps;
}
/**
* Search role.
*/
private List<String> searchRole(String resCode,
List<BaseRoleResource> roleResourceList) {
List<String> result = new ArrayList<String>();
for (Iterator<BaseRoleResource> iterator = roleResourceList.iterator(); iterator
.hasNext();) {
BaseRoleResource baseRoleResource = (BaseRoleResource) iterator
.next();
if (resCode.equals(baseRoleResource.getResourceId())) {
result.add(baseRoleResource.getRoleId());
iterator.remove();
}
}
return result;
}
// According to a URL, Find out permission configuration of this URL.
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.SecurityMetadataSource#getAttributes
* (java.lang.Object)
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
//SpringSecurity会调用此方法,根据URL获取拥有该URL的角色
//如果没有就返回一个DENY的SecurityConfig
String url = ((FilterInvocation) object).getRequestUrl();
url = getTrueUrl(url);
Map<String, Collection<ConfigAttribute>> resourceMap = getResourceMap();
Collection<ConfigAttribute> cca = resourceMap.get(url);
if (cca == null || cca.size() < 1) {
cca = new ArrayList(1);
ConfigAttribute ca = new SecurityConfig("DENY");
cca.add(ca);
}
return cca;
}
/**
* Gets the true url.
*
* @author 596570
* @date 2014-12-8 20:41:07
* @since
* @param url
* the url
* @return the true url
*/
private String getTrueUrl(String url) {
//处理URL,去其参数
int index = url.indexOf("?");
if (index > 0) {
url = url.substring(0, index);
}
return url;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.SecurityMetadataSource#supports(java
* .lang.Class)
*/
public boolean supports(Class<?> clazz) {
return true;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.access.SecurityMetadataSource#
* getAllConfigAttributes()
*/
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
/**
* Refresh resource.
*
* @author 596570
* @date 2014-12-8 20:41:07
* @since
*/
public void refreshResource() {
try {
//清除缓存中的资源集合,让其重新从数据库中加载
CacheUtil.removeKey(CacheConstant.OMS_RESOURCE_MAP);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
}
7.BaseAuthenticationSuccessHandler
/**
*
* BaseAuthenticationSuccessHandler.java
*
*/
package com.sf.oms.security.spring;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import com.sf.oms.common.base.BaseUserDetail;
import com.sf.oms.common.log.dto.LoginLog;
import com.sf.oms.common.log.service.LoginLogService;
import com.sf.oms.security.user.dto.BaseUser;
/**
* The Class BaseAuthenticationSuccessHandler.
*/
@SuppressWarnings("unused")
public class BaseAuthenticationSuccessHandler extends
SavedRequestAwareAuthenticationSuccessHandler {
/** The Constant USER_AGENT. */
private static final String USER_AGENT = "User-Agent";
/** The Constant logger. */
private static final Logger LOGGER = LoggerFactory
.getLogger(BaseAuthenticationSuccessHandler.class);
/** The login log service. */
@Autowired
private LoginLogService loginLogService;
/* (non-Javadoc)
* @see org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler#onAuthenticationSuccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
*/
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
LOGGER.debug(
"用户:{}在时间{},IP地址为{}登录成功!",
new Object[] { authentication.getPrincipal(),
new Timestamp(new Date().getTime()),
request.getRemoteAddr() });
LoginLog login = new LoginLog();
// modify by wds 20141048,user-agent,去掉特殊字符,防止XSS注入
String agent = request.getHeader(USER_AGENT);
agent = agent.replace("<", "").replace(">", "").replace("%", "")
.replace("/", "");
login.setAgent(agent);
// login.setIp(request.getRemoteAddr());
String ip = getIpAddr(request);
String serverIp=getLocalIP();//服务器节点Ip
login.setIp(ip);
login.setServerIp(serverIp);
login.setUserId(((BaseUserDetail) authentication.getPrincipal())
.getUserName());
login.setLoginTime(new Timestamp(new Date().getTime()));
this.loginLogService.insertLog(login);
super.onAuthenticationSuccess(request, response, authentication);
}
/**
* Sets the login log service.
*
*/
public void setLoginLogService(LoginLogService loginLogService) {
this.loginLogService = loginLogService;
}
/**
* Gets the ip addr.
*/
private String getIpAddr(HttpServletRequest request) {
String ipAddress = null;
// ipAddress = this.getRequest().getRemoteAddr();
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0
|| "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0
|| "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0
|| "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if ("127.0.0.1".equals(ipAddress)) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
LOGGER.error(e.getMessage(), e);
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
return ipAddress;
}
/**
* 获取本机的IP地址
* 目的:可记录用户访问系统时被分配到某个节点为,方便日志查询
*
* @date 2014年12月22日 上午10:15:46
* @author 596570
* @since V2.2
* @return 本机的IP地址
*/
public String getLocalIP(){
InetAddress addr = null;
try {
addr = InetAddress.getLocalHost();
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
byte[] ipAddr = addr.getAddress();
String ipAddrStr = "";
for (int i = 0; i < ipAddr.length; i++) {
if (i > 0) {
ipAddrStr += ".";
}
ipAddrStr += ipAddr[i] & 0xFF;
}
return ipAddrStr;
}
}
8.配置文件中的变量参数
cas.logoutUrl=http://cas.sit.com/cas/logout?service=http://localhost:10008/oms-front/base/login.jsp
cas.service=http://localhost:10008/oms-front/j_spring_cas_security_check
cas.loginUrl=http://cas.sit.com/cas/login
cas.ServerUrlPrefix=http://cas.sit.com/cas
9.所需jar包
//cas
compile group: "cas", name: "cas-client-core", version:"3.2.1"
compile group: "cas", name: "sf-framework-share-cas", version:"1.7.9"
compile group: "cas", name: "sf-cas-encrypt", version:"1.4"
compile group: "cas", name: "spring-security-cas", version:"3.1.0.RC3"
主要参考:http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105392230e54f73c6f888b442282c45f93130a1c187bb8e7737f0704a5932b2152f4174bea863c72320925a09bbfd20c82e5866d72c8713b214fc75612a248e88a00789e37912aacf849f0bb8069cfea8f828c1208970f127bf0b2cb01444f9438a54326e2d6ce0c460157e9ab6d25&p=9a6cc64ad4af19ff57ee9478445d88&newp=9a79c54ad5c347e940fec92d02148a231610db2151d2d601298ffe0cc4241a1a1a3aecbf26241a00d0c77c6500a84e56e8fa3076350834f1f689df08d2ecce7e69903469&user=baidu&fm=sc&query=cas+customWebInvocationPrivilegeEvaluator&qid=c5838a270000c537&p1=3