网上自定义Filter的实现很多,这里我提供一种Springboot在代码中的实现。
Shiro提供的Filter我这里不一一介绍了,一般基于web会话的都是使用authc(这是FormAuthenticationFilter)。根据我无状态的登陆需求,选择了AccessControlFilter,网上也有说这个是最被广泛使用的,具体还是看自己需求吧。
Filter代码:
/**
* @author Created by pangkunkun on 2017/11/18.
*/
public class MyAccessControlFilter extends AccessControlFilter {
private static final Logger log= LoggerFactory.getLogger(MyAccessControlFilter.class);
/**
*
* 表示是否允许访问;mappedValue就是[urls]配置中拦截器参数部分,如果允许访问返回true,否则false;
* (感觉这里应该是对白名单(不需要登录的接口)放行的)
* 如果isAccessAllowed返回true则onAccessDenied方法不会继续执行
* 这里可以用来判断一些不被通过的链接(个人备注)
* * 表示是否允许访问 ,如果允许访问返回true,否则false;
* @param servletRequest
* @param servletResponse
* @param object 表示写在拦截器中括号里面的字符串 mappedValue 就是 [urls] 配置中拦截器参数部分
* @return
* @throws Exception
* */
@Override
public boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object object) throws Exception{
// Subject subject = getSubject(servletRequest,servletResponse);
// String url = getPathWithinApplication(servletRequest);
// log.info("当前用户正在访问的 url => " + url);
// log.info("subject.isPermitted(url);"+subject.isPermitted(url));
return false;
}
/**
* 表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。
* onAccessDenied是否执行取决于isAccessAllowed的值,如果返回true则onAccessDenied不会执行;如果返回false,执行onAccessDenied
* 如果onAccessDenied也返回false,则直接返回,不会进入请求的方法(只有isAccessAllowed和onAccessDenied的情况下)
* */
@Override
public boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception{
System.out.println("onAccessDenied");
String username=request.getParameter(Constant.CRS_KEY);
String signature=request.getParameter(Constant.SIGNATURE);
String type=request.getParameter("type");
//TODO 通过其它参数验证signature的正确性
String digestValue=MD5Utils.MD5SendParame(signature);
MyUsernamePasswordToken token=new MyUsernamePasswordToken(username,type, digestValue);
Subject subject= SecurityUtils.getSubject();
try {
subject.login(token);
}catch (Exception e){
log.info("登陆失败");
log.info(e.getMessage());
onLoginFail(response);
return false;
}
log.info("登陆成功");
return true;
}
继承这个filter 要实现两个方法,每个方法我都有给出解释。
isAccessAllowed这里,根据从网上找的实现,我感觉这个是类似白名单被放行的。如果有些特殊的url不需要登录,可以直接在这里通过,或者做其它的判断。当然,这里也可以砸Shiro配置中直接把相应的方法对应的filter栏设置成none,同样不会经过这里。
onAccessDenied是我主要逻辑功能处理的模块。在这里主要是UsernamePasswordToken这块,生成token对象后使用subject进行登录,以便后边方法中权限/角色的验证。
将自定义filter集成进shiro配置:
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
log.info("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//自定义拦截器
Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
filtersMap.put("myAccessControlFilter", new MyAccessControlFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
//拦截器.
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
filterChainDefinitionMap.put("/createPermission", "anon");
filterChainDefinitionMap.put("/**", "myAccessControlFilter");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
//自定义拦截器
Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
filtersMap.put("myAccessControlFilter", new MyAccessControlFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
这块代码是将自定义的拦截器设置进shiro的filterchain中。
filterChainDefinitionMap.put("/**", "myAccessControlFilter");
这里是设置使用自定义拦截器的url。我这里设置的是,如果没有其他拦截器定义的,都有走这个自定义的拦截器。
完整代码可以参考我前面文章Spring Boot集成无状态Shiro–内容详细介绍。