开发者社区> aielves> 正文

shiro安全框架扩展教程--如何扩展异步(ajax)请求认证失败处理

简介:         上一个章节我们学习了如何自定义自己的filter,这个只是为了这一章打基础;相信我们这一群shiro使用者比较关注异步请求认证失败会如何处理这个问题,确实我们现在的项目很大一...
+关注继续查看

        上一个章节我们学习了如何自定义自己的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方法提供我们的异步请求分支处理


欢迎拍砖...

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【Django框架】学习及其【数据库对接技术】 学习&&开发笔记【入门篇】
【Django框架】学习及其【数据库对接技术】 学习&&开发笔记【入门篇】
62 0
Asp.net安全架构之3:CSRF(跨站点请求伪造)
原理 CSRF,Cross Site Request Forgery,即跨站点请求伪造。 这种攻击是指,在用户正常登录系统以后,攻击者诱使用户访问一些非法链接,以执行一些非法操作。比如:如果删除用户操作(如,yourdomain.com/deluser?id=123)没有经过防范CSRF的处理,那么,假设用户登录系统后,攻击者诱使用户同时访问了攻击者的站点的一个链接(该链接正好为yourdomain.com/deluser?id=123),那么,系统就会在用户不知情的情况下丢失一个用户。
747 0
阿里云ACP认证考试细则须知与考题内容学习方法分享
阿里云大数据专业认证(ACP 级-Alibaba Cloud CertificationProfessional)是面向使用阿里云大数据产品的架构、开发、运维类人员的专业技术认证,主要涉及阿里云大数据类的几款核心产品,包括大数据计算服务MaxCompute、数据工场 DataWorks(原大数据开发套件 DataIDE)、数据集成、QuickBI、机器学习 PAI 等。
3735 0
Java秒杀系统实战系列~整合Shiro实现用户登录认证
本篇博文是“Java秒杀系统实战系列文章”的第五篇,在本篇博文中,我们将整合权限认证-授权框架Shiro,实现用户的登陆认证功能,主要用于:要求用户在抢购商品或者秒杀商品时,限制用户进行登陆!并对于特定的url(比如抢购请求对应的url)进行过滤(即当用户访问指定的url时,需要要求用户进行登陆)。
3667 0
用Spry框架来简化AJAX
用Spry框架来简化AJAX Spry AJAX框架是一个面向Web设计者的JavaScript库。它提供了很多供设计者建立页面的扩展功能,AJAX风格。目前其最新版本为2007.5.17日发布的1.5版本。
616 0
【安全合规】python爬虫从0到1 -Requests库的基本使用(get/post请求)
python爬虫从0到1 -Requests库的基本使用(get/post请求)
15 0
+关注
aielves
一直在超越,从未被模仿...
49
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载