用户权限模块之spring security

准备工作:数据库采用mysql(5.6及以上)

CREATE TABLE `auth_system` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`NAME` varchar(100) DEFAULT NULL COMMENT '系统名称',
`URL` varchar(100) DEFAULT NULL COMMENT '系统地址',
`description` varchar(100) DEFAULT NULL COMMENT '描述',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='认证系统表';

CREATE TABLE `auth_user` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`USERNAME` varchar(100) NOT NULL COMMENT '用户名',
`NAME` varchar(100) DEFAULT NULL COMMENT '用户姓名',
`PASSWORD` varchar(500) NOT NULL COMMENT '密码',
`LAST_LOGIN` datetime DEFAULT NULL COMMENT '最后登录日期',
`DEADLINE` datetime DEFAULT NULL COMMENT '截止日期',
`LOGIN_IP` varchar(100) DEFAULT NULL COMMENT '最后登录IP',
`ENABLED` char(1) DEFAULT NULL COMMENT 'ENABLED',
`ACCOUNT_NON_EXPIRED` char(1) DEFAULT NULL COMMENT '是否过期',
`ACCOUNT_NON_LOCKED` char(1) DEFAULT NULL COMMENT '是否锁定',
`CREDENTIALS_NON_EXPIRED` char(1) DEFAULT NULL COMMENT '用户证书是否有效',
`SYSTEM_ID` int(11) DEFAULT NULL COMMENT '系统ID',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8 COMMENT='认证用户表';

CREATE TABLE `auth_user_role` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`ROLE_ID` int(11) NOT NULL COMMENT '角色ID',
`USER_ID` int(11) NOT NULL COMMENT '用户ID',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=266 DEFAULT CHARSET=utf8 COMMENT='认证用户角色表';

 

CREATE TABLE `auth_role` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`ROLE_NAME` varchar(100) DEFAULT NULL COMMENT '角色名称',
`ROLE_DESC` varchar(200) DEFAULT NULL COMMENT '角色描述',
`ENABLE` int(11) DEFAULT NULL COMMENT '启用状态',
`ISSYS` int(11) DEFAULT NULL COMMENT 'ISSYS',
`MODULE_ID` varchar(100) DEFAULT NULL COMMENT '模块ID',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
`SYSTEM_ID` int(11) DEFAULT NULL COMMENT '系统ID',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=119 DEFAULT CHARSET=utf8 COMMENT='认证角色表';

 

CREATE TABLE `auth_role_authority` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`ROLE_ID` int(11) NOT NULL COMMENT '角色ID',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
`AUTHORITY_ID` int(11) NOT NULL COMMENT '权限ID',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=159 DEFAULT CHARSET=utf8 COMMENT='认证角色权限表';

 

CREATE TABLE `auth_authority` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`AUTHORITY_MARK` varchar(100) DEFAULT NULL COMMENT '权限标示',
`AUTHORITY_NAME` varchar(100) NOT NULL COMMENT '权限名称',
`AUTHORITY_DESC` varchar(200) DEFAULT NULL COMMENT '权限描述',
`MESSAGE` varchar(100) DEFAULT NULL COMMENT '提示信息',
`ENABLE` char(1) DEFAULT NULL COMMENT 'ENABLE',
`ISSYS` char(1) DEFAULT NULL COMMENT 'ISSYS',
`MODULE_ID` int(11) DEFAULT NULL COMMENT '模块ID',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
`SYSTEM_ID` int(11) DEFAULT NULL COMMENT '系统ID',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8 COMMENT='认证权限表';

CREATE TABLE `auth_authority_resource` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`RESOURCE_ID` int(11) NOT NULL COMMENT '资源ID',
`AUTHORITY_ID` int(11) NOT NULL COMMENT '权限ID',
`CREATED_DT` datetime DEFAULT NULL COMMENT '创建时间',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`ID`),
KEY `FK_SYS_AUTH_REFERENCE_SYS_AUTH` (`AUTHORITY_ID`),
KEY `FK_SYS_AUTH_REFERENCE_SYS_RESO` (`RESOURCE_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=6112 DEFAULT CHARSET=utf8 COMMENT='认证权限资源表';

 

CREATE TABLE `auth_resource` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '资源ID',
`RESOURCE_TYPE` varchar(100) DEFAULT NULL COMMENT '资源类型',
`RESOURCE_NAME` varchar(100) DEFAULT NULL COMMENT '资源名称',
`RESOURCE_DESC` varchar(200) DEFAULT NULL COMMENT '资源描述',
`RESOURCE_PATH` varchar(200) DEFAULT NULL COMMENT '资源路径',
`PRIORITY` varchar(100) DEFAULT NULL COMMENT '优先次序',
`ENABLE` char(1) DEFAULT NULL COMMENT 'ENABLE',
`ISSYS` char(1) DEFAULT NULL COMMENT 'ISSYS',
`MODULE_ID` varchar(100) DEFAULT NULL COMMENT '模块ID',
`create_dt` datetime DEFAULT NULL COMMENT 'create_dt',
`create_by` int(11) DEFAULT NULL COMMENT 'create_by',
`last_update_dt` datetime DEFAULT NULL COMMENT '最后更新时间',
`last_update_by` int(11) DEFAULT NULL COMMENT '最后更新人',
`sts` char(1) DEFAULT NULL COMMENT '状态',
`SYSTEM_ID` int(11) DEFAULT NULL COMMENT '系统ID',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=550 DEFAULT CHARSET=utf8 COMMENT='认证资源表';

 主要用到以上这些表,准备工作完毕,开始进入正题

要使用spring security来作为权限控制,在完成如上的数据库设计后,

采用maven作为构建工具:

<spring.security.version>3.2.6.RELEASE</spring.security.version>

<!--spring security-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
<exclusions>
<exclusion>
<artifactId>spring-asm</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>

在web.xml中加上

<!--security-->
<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>

该配置作用是让spring security对所有请求进行拦截,

我们需要加一个spring的配置文件 application-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
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.2.xsd
http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
">

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:security.properties</value>
</property>
</bean>

<!-- 配置不过滤的资源(静态资源及登录相关) -->
<sec:http pattern="/**/*.css" security="none"></sec:http>
<sec:http pattern="/**/*.jpg" security="none"></sec:http>
<sec:http pattern="/**/*.jpeg" security="none"></sec:http>
<sec:http pattern="/**/*.gif" security="none"></sec:http>
<sec:http pattern="/**/*.png" security="none"></sec:http>
<sec:http pattern="/**/*.js" security="none"></sec:http>
<sec:http pattern="/static/**" security="none"></sec:http>

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


<bean id="customUserDetailsService" class="com.linxingall.auth.security.DefaultUserDetailsService"></bean>
<bean id="authenticationSuccessHandler" class="com.linxingall.auth.security.SimpleLoginSuccessHandler">
<property name="defaultTargetUrl" value="${success.url}"></property>
<property name="forwardToDestination" value="false"></property>
</bean>
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login" />
</bean>
<sec:http access-decision-manager-ref="accessDecisionManager"
entry-point-ref="authenticationEntryPoint">

<sec:access-denied-handler ref="accessDeniedHandler"/>

<sec:session-management invalid-session-url="/login" />
<sec:custom-filter ref="logoutFilter" position="LOGOUT_FILTER" />
<sec:custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"/>
<sec:custom-filter ref="rememberMeFilter" position="REMEMBER_ME_FILTER"/>
<sec:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>
</sec:http>



<bean id="rememberMeFilter"
class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices" />
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<!-- RememberMeServices的实现 -->
<bean id="rememberMeServices"
class="com.linxingall.auth.security.CustomTokenBasedRememberMeServices">
<property name="userDetailsService" ref="customUserDetailsService" />
<property name="tokenValiditySeconds" value="43200"/>
<property name="key" value="abcd"/>
<property name="cookieName" value="remember_me"/>
<!-- 指定request中包含的用户是否选择了记住我的参数名 -->
<property name="parameter" value="remember_me"/>
<property name="alwaysRemember" value="true"/>
<property name="rootPath" value="false"/>
</bean>
<!-- key值需与对应的RememberMeServices保持一致 -->
<bean id="rememberMeAuthenticationProvider"
class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="abcd" />
</bean>

<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<property name="filterProcessesUrl" value="/logout"/>
<constructor-arg index="0" value="/login"/>
<constructor-arg index="1">
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"></bean>
<bean class="com.linxingall.auth.security.CustomCookieClearingLogoutHandler">
<constructor-arg>
<list>
<value>JSESSIONID</value>
<value>JSESSIONID</value>
<value>JSESSIONID</value>
<value>remember_me</value>
</list>
</constructor-arg>
<property name="splitChar" value="@"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="loginFilter" class="com.linxingall.auth.security.DefaultUsernamePasswordAuthenticationFilter">
<property name="usernameParameter" value="username"></property>
<property name="passwordParameter" value="password"></property>
<property name="filterProcessesUrl" value="/login.do"></property>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationFailureHandler">
<bean class="com.linxingall.auth.security.CustomUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login"></property>
</bean>
</property>
</bean>
<bean id="filterSecurityInterceptor" class="com.linxingall.auth.security.CustomFilterSecurityInterceptor">
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="authenticationManager" ref="authenticationManager" />
<property name="securityMetadataSource" ref="securityMetadataSource" />
</bean>

<bean id="securityMetadataSource"
class="com.linxingall.auth.security.URLFilterInvocationSecurityMetadataSource"/>

<!-- 自定义权限不足处理程序 -->
<bean id="accessDeniedHandler" class="com.linxingall.auth.security.DefaultAccessDeniedHandler">
<property name="errorPage" value="/403"></property>
</bean>

<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="authenticationProvider" />
<sec:authentication-provider ref="rememberMeAuthenticationProvider"/>
</sec:authentication-manager>


<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="hideUserNotFoundExceptions" value="false" />
<property name="userDetailsService" ref="customUserDetailsService" />
<property name="passwordEncoder" ref="passwordEncode" />
<!--<property name="saltSource" ref="saltSource" />-->
</bean>



<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg name="decisionVoters">
<list>
<ref bean="roleVoter"/>
<ref bean="authenticatedVoter"/>
</list>
</constructor-arg>
</bean>

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
<property name="rolePrefix" value=""></property>
</bean>

<bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter" />

<!-- 配置密码加密类 -->
<bean id="passwordEncode" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

<!--<bean id="passwordEncode" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />-->
<bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">
<property name="userPropertyToUse" value="username"/>
</bean>

</beans>
接下来为java类;
DefaultUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter
重写
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
try {
if (!CaptchaServiceSingleton.getInstance().validateResponseForID(request.getSession().getId(), request.getParameter("validateCode"))) {
throw new CaptchaException("");
}
} catch (CaptchaServiceException e) {
throw new CaptchaException("");
}
//校验是否拥有当前系统访问权限
if(!userService.hasSystemPermistion(this.obtainUsername(request),request.getRequestURI(),request.getContextPath())){
throw new AuthenticationServiceException("");
}
return super.attemptAuthentication(request, response);
}
UserService
@Override
public boolean hasSystemPermistion(String userName, String requestUrl, String basePath) {
Preconditions.checkArgument(StringUtils.isNotBlank(userName),"user name cannot be null!");
List<UserDo> userDos = getUserDo(userName);
if(CollectionUtils.isNotEmpty(userDos)){
Integer systemId = userDos.get(0).getSystemId();
//用户未配置系统默认能登陆所有系统
if(systemId!=null){
AuthSystemDo authSystemDo = authSystemDao.selectByPrimaryKey(systemId);
if(authSystemDo!=null){
String systemUrl = authSystemDo.getUrl();
if(StringUtils.startsWith(systemUrl,"/")){
//网址配置“/”开头的系统比较上下文路径
if (!StringUtils.equals(basePath,systemUrl)) {
return false;
}
}else{
//其他比较全网址是否以系统配置的网址开头
if(!StringUtils.startsWith(requestUrl,systemUrl)){
return false;
}
}
}
}
}else{
//用户不存在 返回无权限
return false;
}
return true;
}

CustomTokenBasedRememberMeServices 

public class CustomTokenBasedRememberMeServices extends TokenBasedRememberMeServices implements MessageSourceAware {


protected MessageSourceAccessor message;

@Autowired
private UserService userService;

private boolean rootPah = false;

public boolean isRootPah() {
return rootPah;
}

public void setRootPah(boolean rootPah) {
this.rootPah = rootPah;
}

@Override
protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request, HttpServletResponse response) {
if(cookieTokens.length != 3) {
throw new InvalidCookieException("Cookie token did not contain 3 tokens, but contained \'" + Arrays.asList(cookieTokens) + "\'");
}
//校验是否拥有当前系统访问权限
if(!userService.hasSystemPermistion(cookieTokens[0],request.getRequestURI(),request.getContextPath())){
throw new AccessDeniedException(this.message.getMessage("custom.error.auth.system.error"
,new String[]{cookieTokens[0]}));
}
return super.processAutoLoginCookie(cookieTokens, request, response);
}

@Override
protected void setCookie(String[] tokens, int maxAge, HttpServletRequest request, HttpServletResponse response) {
String cookieValue = this.encodeCookie(tokens);
Cookie cookie = new Cookie(this.getCookieName(), cookieValue);
if(hasRememberMeParam(request,this.getParameter())) {
cookie.setMaxAge(maxAge);
}
if(this.rootPah){
cookie.setPath("/");
}else {
cookie.setPath(this.getCookiePath(request));
}
if (maxAge < 1) {
cookie.setVersion(1);
}
cookie.setSecure(request.isSecure());
//ReflectionUtils.invokeMethod(this.setHttpOnlyMethod, cookie, new Object[]{Boolean.TRUE});
response.addCookie(cookie);
}
@Override
protected void cancelCookie(HttpServletRequest request, HttpServletResponse response) {
this.logger.debug("Cancelling cookie");
Cookie cookie = new Cookie(this.getCookieName(), (String)null);
cookie.setMaxAge(0);
if(this.rootPah) {
cookie.setPath("/");
}else{
cookie.setPath(this.getCookiePath(request));
}
response.addCookie(cookie);
}

protected boolean hasRememberMeParam(HttpServletRequest request, String parameter) {
String paramValue = request.getParameter(parameter);
if(paramValue != null && (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on") || paramValue.equalsIgnoreCase("yes") || paramValue.equals("1"))) {
return true;
} else {
return false;
}
}
private String getCookiePath(HttpServletRequest request) {
String contextPath = request.getContextPath();
return contextPath.length() > 0?contextPath:"/";
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.message = new MessageSourceAccessor(messageSource) ;
}
}


CustomCookieClearingLogoutHandler
public class CustomCookieClearingLogoutHandler implements LogoutHandler {
private String splitChar ="/";
private final List<String> cookiesToClear;

public CustomCookieClearingLogoutHandler(String... cookiesToClear) {
Assert.notNull(cookiesToClear, "List of cookies cannot be null");
this.cookiesToClear = Arrays.asList(cookiesToClear);
}

public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
Iterator i$ = this.cookiesToClear.iterator();

while(i$.hasNext()) {
String cookieName = (String)i$.next();
String cookiePath = request.getContextPath();

if(StringUtils.indexOf(cookieName, splitChar)>0){
cookiePath = cookieName.split(splitChar)[1];
cookieName = cookieName.split(splitChar)[0];
}

Cookie cookie = new Cookie(cookieName, (String)null);

cookie.setPath(cookiePath);
cookie.setMaxAge(0);
response.addCookie(cookie);
}

}
private String getCookiePath(HttpServletRequest request,String cookieName){
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if(cookie!=null && StringUtils.equals(cookieName,cookie.getName())){
if(StringUtils.isNotBlank(cookie.getPath())){
return cookie.getPath();
}
}
}
return "/";
}

public void setSplitChar(String splitChar) {
this.splitChar = splitChar;
}
}

CustomFilterSecurityInterceptor
public class CustomFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

private FilterInvocationSecurityMetadataSource securityMetadataSource;


public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return securityMetadataSource;
}

public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
this.securityMetadataSource = securityMetadataSource;
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
FilterInvocation fileInvocation = new FilterInvocation(servletRequest, servletResponse, filterChain);
InterceptorStatusToken interceptorStatusToken = this
.beforeInvocation(fileInvocation);
fileInvocation.getChain().doFilter(servletRequest, servletResponse);
this.afterInvocation(interceptorStatusToken, null);
}

@Override
public void destroy() {

}

@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}

@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
}

URLFilterInvocationSecurityMetadataSource
public class URLFilterInvocationSecurityMetadataSource implements
FilterInvocationSecurityMetadataSource,InitializingBean {
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
protected final Log logger = LogFactory.getLog(getClass());

//权限集合
private Map<RequestMatcher, Collection<ConfigAttribute>> ALL_RESOURCE_AUTHORITIS;

@Autowired
private ResourceDao resourceDao;

/* (non-Javadoc)
* @see org.springframework.security.access.SecurityMetadataSource#getAttributes(java.lang.Object)
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
final HttpServletRequest request = ((FilterInvocation) object).getRequest();

Collection<ConfigAttribute> attrs = Lists.newArrayList();

for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : ALL_RESOURCE_AUTHORITIS.entrySet()) {
if (entry.getKey().matches(request)) {
attrs.addAll(entry.getValue());
}
}
logger.info("URL资源:"+request.getRequestURI()+ " -> " + attrs);
if(CollectionUtils.isEmpty(attrs)){
throw new AccessDeniedException(this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
}
return attrs;
}

/* (non-Javadoc)
* @see org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes()
*/
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();
for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : ALL_RESOURCE_AUTHORITIS.entrySet()) {
allAttributes.addAll(entry.getValue());
}
return allAttributes;
}

/* (non-Javadoc)
* @see org.springframework.security.access.SecurityMetadataSource#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}


private Map<RequestMatcher, Collection<ConfigAttribute>> getResourceAuthoritis(){
Map<RequestMatcher, Collection<ConfigAttribute>> resultMap = Maps.newHashMap();
List<ResourceAuthDo> list = resourceDao.listAllResourceAuths();
for (ResourceAuthDo resourceAuthDo : list) {
CustomAntPathRequestMatcher matcher = new CustomAntPathRequestMatcher(resourceAuthDo.getResourcePath(),resourceAuthDo.getSystemUrl());
if(resultMap.containsKey(matcher)){
resultMap.get(matcher).add(new SecurityConfig(resourceAuthDo.getAuthorityMark()));
}else{
resultMap.put(matcher, SecurityConfig.createList(resourceAuthDo.getAuthorityMark()));
}
}
return resultMap;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
* 初始化权限列表
*/
@Override
public void afterPropertiesSet() throws Exception {
refreshResourceAuthoritis();
}

public void refreshResourceAuthoritis(){
this.ALL_RESOURCE_AUTHORITIS = this.getResourceAuthoritis();
}
}
DefaultAccessDeniedHandler
public class DefaultAccessDeniedHandler implements AccessDeniedHandler {
/* (non-Javadoc)
* @see org.springframework.security.web.access.AccessDeniedHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.access.AccessDeniedException)
*/
private String errorPage;

//~ Methods ========================================================================================================

public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
throws IOException, ServletException {
boolean isAjax = ControllerUtils.isAjaxRequest(request);
if(isAjax){
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();


JSONObject message = new JSONObject();
message.put("code","403");
message.put("message",accessDeniedException.getMessage());
writer.print(message.toString());
}else if (!response.isCommitted()) {
if (errorPage != null) {
// Put exception into request scope (perhaps of use to a view)
request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);

// Set the 403 status code.
response.setStatus(HttpServletResponse.SC_FORBIDDEN);

// forward to error page.
RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
//将错误信息设置至请求头上
request.setAttribute("message",accessDeniedException.getMessage());
dispatcher.forward(request, response);
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}
}

/**
* The error page to use. Must begin with a "/" and is interpreted relative to the current context root.
*
* @param errorPage the dispatcher path to display
*
* @throws IllegalArgumentException if the argument doesn't comply with the above limitations
*/
public void setErrorPage(String errorPage) {
if ((errorPage != null) && !errorPage.startsWith("/")) {
throw new IllegalArgumentException("errorPage must begin with '/'");
}

this.errorPage = errorPage;
}
}


 

posted @ 2017-06-01 10:37  linxxxyz  阅读(1701)  评论(1编辑  收藏  举报