上一个章节我们学习了如何自定义自己的filter,这个只是为了这一章打基础;相信我们这一群shiro使用者比较关注异步请求认证失败会如何处理这个问题,确实我们现在的项目很大一部分请求都是异步的,所以这个问题是无可避免,我看了网上很多资料都是没有完整地给出扩展方案,下面我把自己的处理方案给展示下,如有不爽,请勿跨省,家无水表,不收快递...
直接进入主题,先看看我们之前的配置,自定义一个RoleAuthorizationFilter
<!-- 过滤链配置 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/" />
<property name="successUrl" value="/cms/index.do" />
<property name="unauthorizedUrl" value="/" />
<property name="filters">
<map>
<entry key="role">
<bean
class="com.silvery.security.shiro.filter.RoleAuthorizationFilter" />
</entry>
<entry key="authc">
<bean
class="com.silvery.security.shiro.filter.SimpleFormAuthenticationFilter" />
</entry>
</map>
</property>
</bean>
<!-- 权限资源配置 -->
<bean id="filterChainDefinitionsService"
class="com.silvery.security.shiro.service.impl.SimpleFilterChainDefinitionsService">
<property name="definitions">
<value>
/static/** = anon
/admin/user/login.do = anon
/test/** = role[admin]
/abc/** = authc
</value>
</property>
</bean>
public class RoleAuthorizationFilter extends AuthorizationFilter {
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws IOException {
Subject subject = getSubject(request, response);
String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) {
// no roles specified, so nothing to check - allow access.
return true;
}
Set<String> roles = CollectionUtils.asSet(rolesArray);
for (String role : roles) {
if (subject.hasRole(role)) {
return true;
}
}
return false;
}
}
我们先看看这个源码,发现是继承了AuthorizationFilter类,然后只重写了isAccessAllowed方法,然后我们就想isAccessAllowed是判断是否拥有权限,那肯定会有一个方法是认证失败回调的方法,这是框架一贯的做法,来验证下我们的想当然是不是正确的,我们打开AuthorizationFilter类的源码看看
public abstract class AuthorizationFilter extends AccessControlFilter
{
public AuthorizationFilter()
{
}
public String getUnauthorizedUrl()
{
return unauthorizedUrl;
}
public void setUnauthorizedUrl(String unauthorizedUrl)
{
this.unauthorizedUrl = unauthorizedUrl;
}
protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
throws IOException
{
Subject subject = getSubject(request, response);
if(subject.getPrincipal() == null)
{
saveRequestAndRedirectToLogin(request, response);
} else
{
String unauthorizedUrl = getUnauthorizedUrl();
if(StringUtils.hasText(unauthorizedUrl))
WebUtils.issueRedirect(request, response, unauthorizedUrl);
else
WebUtils.toHttp(response).sendError(401);
}
return false;
}
private String unauthorizedUrl;
}
看到源码的时候我就很开心地贱笑了,果然是我想的那样,我们很明显地看到一个方法onAccessDenied,认证失败处理,逻辑就是如果登录实体为null就保存请求和跳转登录页面,否则就跳转无权限配置页面
我们开始动手改造这个方法,把这个方法也在我们自己的RoleAuthorizationFilter里重写下
/**
*
* 1.自定义角色鉴权过滤器(满足其中一个角色则认证通过) 2.扩展异步请求认证提示功能;
*
* @author shadow
*
*/
public class RoleAuthorizationFilter extends AuthorizationFilter {
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
Subject subject = getSubject(request, response);
if (subject.getPrincipal() == null) {
if (com.silvery.utils.WebUtils.isAjax(httpRequest)) {
com.silvery.utils.WebUtils.sendJson(httpResponse, JsonUtils.toJSONString(new ViewResult(false,
"您尚未登录或登录时间过长,请重新登录!")));
} else {
saveRequestAndRedirectToLogin(request, response);
}
} else {
if (com.silvery.utils.WebUtils.isAjax(httpRequest)) {
com.silvery.utils.WebUtils.sendJson(httpResponse, JsonUtils.toJSONString(new ViewResult(false,
"您没有足够的权限执行该操作!")));
} else {
String unauthorizedUrl = getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl)) {
WebUtils.issueRedirect(request, response, unauthorizedUrl);
} else {
WebUtils.toHttp(response).sendError(401);
}
}
}
return false;
}
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws IOException {
Subject subject = getSubject(request, response);
String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) {
// no roles specified, so nothing to check - allow access.
return true;
}
Set<String> roles = CollectionUtils.asSet(rolesArray);
for (String role : roles) {
if (subject.hasRole(role)) {
return true;
}
}
return false;
}
}
其实改造也很简单,只是再加一层ajax的判断,至于如何判断ajax就是自己个人的方式,有的项目喜欢加一个标识参数,有的人喜欢直接用header里面的X-Requested-With参数,这个看自己的需求咯,我个人喜欢是ajax请求认证失败是返回一串标准的json格式字符串,页面兼容处理也方便
下面我们测试下如何效果,先写一个html,配置/test/a.do是不够权限请求的
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>test ajax request</title>
<script type="text/javascript" src="/static/plugin/jquery/core.js"></script>
<script>
function test(){
$.post('/test/a.do','',function(result){
alert(result);
});
}
</script>
</head>
<body>
<input type="button" value="click" onclick="test();" />
</body>
</html>
html写完,就跑起项目,然后先别登录系统,直接打开html点击下这个按钮,发现alert提示{"message":"您尚未登录或登录时间过长,请重新登录!","success":false,"value":null};
然后再登录系统,再点击这个按钮请求一次看看发现alert提示{"message":"您没有足够的权限执行该操作!","success":false,"value":null};很明显尚未登录和权限不足的ajax时候提示都完美地出现,然后这章节我就可以功成身退了
最后总结下扩展方案,其实shiro的所有filter都是有统一的接口方法,你们可以看看这真实过滤器都是继承了相同的父级filter,所以其他的filter也可以通过继承重写onAccessDenied方法提供我们的异步请求分支处理
欢迎拍砖...
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
赠送jar包:shiro-config-core-1.4.0.jar; 赠送原API文档:shiro-config-core-1.4.0-javadoc.jar; 赠送源代码:shiro-config-core-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-config-core-1.4.0.pom; ...
赠送jar包:shiro-config-core-1.4.0.jar; 赠送原API文档:shiro-config-core-1.4.0-javadoc.jar; 赠送源代码:shiro-config-core-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-config-core-1.4.0.pom; ...
shiro_attack-4.7.0-SNAPSHOT-all.zip 序列化验证工具
给广大开发爱好者一个开发框架:shiro-root-1.4.1-source-release.zip
赠送jar包:shiro-event-1.4.0.jar; 赠送原API文档:shiro-event-1.4.0-javadoc.jar; 赠送源代码:shiro-event-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-event-1.4.0.pom; 包含翻译后的API文档:shiro-...
赠送jar包:shiro-cas-1.2.3.jar; 赠送原API文档:shiro-cas-1.2.3-javadoc.jar; 赠送源代码:shiro-cas-1.2.3-sources.jar; 赠送Maven依赖信息文件:shiro-cas-1.2.3.pom; 包含翻译后的API文档:shiro-cas-...
赠送jar包:shiro-crypto-core-1.4.0.jar; 赠送原API文档:shiro-crypto-core-1.4.0-javadoc.jar; 赠送源代码:shiro-crypto-core-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-crypto-core-1.4.0.pom; ...
赠送jar包:shiro-crypto-cipher-1.4.0.jar; 赠送原API文档:shiro-crypto-cipher-1.4.0-javadoc.jar; 赠送源代码:shiro-crypto-cipher-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-crypto-cipher-1.4.0....
赠送jar包:shiro-core-1.4.0.jar; 赠送原API文档:shiro-core-1.4.0-javadoc.jar; 赠送源代码:shiro-core-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-core-1.4.0.pom; 包含翻译后的API文档:shiro-core...
shiro 安全框架--最好的中文配置文档,讲了shiro的配置步骤
springboot-shiro认证系统框架--成型框架,认证中心服务,分布式框架,可以直接使用,配置多元化,组件化,只需修改配置文件,达到相应需求,适合生产开发,开发学习
赠送jar包:shiro-crypto-core-1.4.0.jar; 赠送原API文档:shiro-crypto-core-1.4.0-javadoc.jar; 赠送源代码:shiro-crypto-core-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-crypto-core-1.4.0.pom; ...
shiro-root-1.2.4-source-release shiro-root-1.2.3-source-release shiro-all-1.2.4.jar shiro-all-1.2.4.jar shiro-all-1.2.4.jar shiro-all-1.2.4.jar
赠送jar包:shiro-config-ogdl-1.4.0.jar; 赠送原API文档:shiro-config-ogdl-1.4.0-javadoc.jar; 赠送源代码:shiro-config-ogdl-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-config-ogdl-1.4.0.pom; ...
shiro使用依赖的所有jar包,以及shiro-root-1.2.3-source-release的zip包
shiro(shiro-all-1.8.0.jar)
基于SpringMVC Mybatis Shiro Redis 的权限管理系统,该系统已经部署到线上,线上访问地址:http://shiro.itboy.net,登录账号:admin 密码:sojson,,详细教程参考sojson.com/shiro
赠送jar包:shiro-spring-1.3.2.jar; 赠送原API文档:shiro-spring-1.3.2-javadoc.jar; 赠送源代码:shiro-spring-1.3.2-sources.jar; 包含翻译后的API文档:shiro-spring-1.3.2-javadoc-API文档-中文(简体)版...
赠送jar包:shiro-crypto-cipher-1.4.0.jar; 赠送原API文档:shiro-crypto-cipher-1.4.0-javadoc.jar; 赠送源代码:shiro-crypto-cipher-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-crypto-cipher-1.4.0....
赠送jar包:shiro-crypto-hash-1.4.0.jar; 赠送原API文档:shiro-crypto-hash-1.4.0-javadoc.jar; 赠送源代码:shiro-crypto-hash-1.4.0-sources.jar; 赠送Maven依赖信息文件:shiro-crypto-hash-1.4.0.pom; ...