spring security的自定义过滤器实现URL过滤

spring security的自定义过滤器实现URL过滤

最近要实现一个功能,在使用spring security判断完成权限后,还要验证一下URL是否能访问。
因为spring security是用的正则表达式,比如:
http://localhost/order/edit.do?id=13343434
拦截的URL就写成 order/edit.do?*,然后定义成为一个“订单”权限赋予用户。但是并不控制,比如这种到数据的关系,比如
id为132434,1343434,13434的这几个只能让部门经理看,id为1343431的只能让创建人看这种需求,要实现这样的需求,我计划的是在权限拦截之后,实现一个自定义的拦截器,调用业务的manager去实现验证。如果通过,向下执行;如果不通过,那么转向到没有数据权限页面。

比较土的办法,不晓得有没有其他好办法,我没有使用到spring security的AnonymousProcessFilter,我们系统内的用户都是要登录的,所以我决定重写这个filter来实现这个URL过滤的功能。

修改security-context.xml配置文件,增加如下内容:
<beans:bean id="customerAnonymousProcessFilter" class="cn.sccl.um.security.CustomerAnonymousProcessingFilter">
<custom-filter before="ANONYMOUS_FILTER" />
<beans:property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS" />
<beans:property name="key" value="springsecurity"/>
</beans:bean>

其中的ANONYMOUS_FILTER是告诉spring的filter链,我要在哪个位置加入我的自定义fitler

类CustomerAnonymousProcessingFilter.java如下,目前没有实现正则判断URL,而只是通过URL去匹配,这里还需要稍微改进下:
package cn.sccl.um.security;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.security.Authentication;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
import org.springframework.security.ui.AuthenticationDetailsSource;
import org.springframework.security.ui.FilterChainOrder;
import org.springframework.security.ui.SpringSecurityFilter;
import org.springframework.security.ui.WebAuthenticationDetailsSource;
import org.springframework.security.userdetails.memory.UserAttribute;
import org.springframework.util.Assert;
import org.springframework.web.context.support.WebApplicationContextUtils;
import cn.sccl.common.ResourceMappingManager;
import cn.sccl.common.ResourceSystemConfiguration;
import cn.sccl.common.util.StringUtil;
public class CustomerAnonymousProcessingFilter extends SpringSecurityFilter
implements InitializingBean {
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
private String key;
private UserAttribute userAttribute;
private boolean removeAfterRequest = true;
public void afterPropertiesSet() throws Exception {
Assert.notNull(userAttribute);
Assert.hasLength(key);
}
protected boolean applyAnonymousForThisRequest(HttpServletRequest request) {
return true;
}
protected Authentication createAuthentication(HttpServletRequest request) {
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(
key, userAttribute.getPassword(), userAttribute
.getAuthorities());
auth.setDetails(authenticationDetailsSource
.buildDetails((HttpServletRequest) request));
return auth;
}

private boolean isJspResources(HttpServletRequest request) {
boolean flag = false;
return flag;
}

protected void doFilterHttp(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (SecurityContextHolder.getContext() != null
&& SecurityContextHolder.getContext().getAuthentication() != null
&& SecurityContextHolder.getContext().getAuthentication()
.isAuthenticated()) {
//获得前面filter登陆的用户loginId
String loginId = SecurityContextHolder.getContext()
.getAuthentication().getName();
//得到请求URL
String url = request.getRequestURI().toLowerCase();
//目前通过properties获得对应的spring bean名称
String managerName = ResourceSystemConfiguration.getResourceMap()
.get(url);
boolean flag = true;
if (StringUtil.isNotBlank(managerName)) {
//要实现资源拦截的manager多implement一个接口ResourceMappingManager
flag = ((ResourceMappingManager) getAppContext(request)
.getBean(managerName)).checkResourceMapping(loginId,
url);
//flag = false; //测试用
if (!flag) {
// 不通过,那么转向没有权限页面
response.sendRedirect(request.getContextPath()
+ "/common/noright.jsp");
return;
}
//放行
}
}
chain.doFilter(request, response);
}

protected ApplicationContext getAppContext(HttpServletRequest request) {
HttpSession session = request.getSession();
ApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(session.getServletContext());
return ctx;
}
public int getOrder() {
return FilterChainOrder.ANONYMOUS_FILTER;
}
public String getKey() {
return key;
}
public UserAttribute getUserAttribute() {
return userAttribute;
}
public boolean isRemoveAfterRequest() {
return removeAfterRequest;
}
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource,
"AuthenticationDetailsSource required");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void setKey(String key) {
this.key = key;
}
public void setRemoveAfterRequest(boolean removeAfterRequest) {
this.removeAfterRequest = removeAfterRequest;
}
public void setUserAttribute(UserAttribute userAttributeDefinition) {
this.userAttribute = userAttributeDefinition;
}
}

用到的类ResourceSystemConfiguration.java如下,这个是参考同事获得properties文件的工具类写的:
package cn.sccl.common;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
public class ResourceSystemConfiguration {
private static CompositeConfiguration config;
private static PropertiesConfiguration propertiesConfig;
static {
config = new CompositeConfiguration();
if (propertiesConfig == null) {
try {
propertiesConfig = new PropertiesConfiguration(
"resouces.properties");
propertiesConfig
.setReloadingStrategy(new FileChangedReloadingStrategy());
config.addConfiguration(propertiesConfig);
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
}
private ResourceSystemConfiguration() {
}
public static String getString(String propertyKey) {
return config.getString(propertyKey);
}
public static String getString(String propertyKey, String defaultValue) {
return config.getString(propertyKey, defaultValue);
}
public static int getInt(String propertyKey) {
return config.getInt(propertyKey);
}
public static int getInt(String key, int defaultValue) {
return config.getInt(key, defaultValue);
}
public static float getFloat(String propertyKey) {
return config.getFloat(propertyKey);
}
public static float getFloat(String propertyKey, float defaultValue) {
return config.getFloat(propertyKey, defaultValue);
}
public static boolean getBoolean(String propertyKey) {
return config.getBoolean(propertyKey);
}
public static boolean getBoolean(String propertyKey, boolean defualtValue) {
return config.getBoolean(propertyKey, defualtValue);
}
public static String[] getStringArray(String propertyKey) {
return config.getStringArray(propertyKey);
}
public static List<String> getStringList(String propertyKey) {
List<String> list = new ArrayList<String>();
String[] strArr = getStringArray(propertyKey);
for (String value : strArr) {
list.add(value);
}
return list;
}
public static Map<String, String> getResourceMap() {
Iterator<?> itkey = config.getKeys();
Map<String, String> map = new HashMap<String, String>();
for (; itkey.hasNext();) {
String key = (String) itkey.next();
String value = config.getString(key);
map.put(key, value);
}
return map;
}
@SuppressWarnings("unchecked")
public static List getList(String propertyKey) {
return config.getList(propertyKey);
}
}

最后一个resources.properties如下,以后可以修改为数据库来存放这个对应关系:
/icpmis/user/edit.do*=userManager,id
我们的UserManagerImpl.java只要实现接口ResourceMappingManager就行了:
public class UserManagerImpl extends BaseManagerImpl<User> implements
UserManager ,ResourceMappingManager
接口ResourceMappingManager.java里面要各个业务manager实现这个接口就行了,到时候MAPPING的这个FITLER就自动调用各个业务方法的MANAGER来验证是否通过:
package cn.sccl.common;
public interface ResourceMappingManager {
public boolean checkResourceMapping(String loginId, String bussinessId);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值