`
TableMiao
  • 浏览: 75414 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

shiro权限管理(二)

阅读更多

 

shiro权限管理(二)

        本篇主要是把权限控制在rest接口端,欢迎圈错,共同学习。

        采用maven的整体构造,提供sql和ws模块。(maven+spring+mybatis+Xmemcached+jetty)。

        贴图为部分代码,文末附上整个项目源码。

 

一、图示流程及效果图

            1.先看数据库表关系和内容


          2.从上图所知道

                用户名为table的用户 ,角色为管理员 ,  拥有user-select 权限;

                用户名为table1的用户, 角色为一般用户 ,不拥有 user-select权限;

         3.用户名table登录

                   

                   登录之后获取角色id和认证头bearer  去访问user-select 权限对应的接口url

                   

                   正常访问得到数据的情况

       

              4.用户名table1登录 没有权限访问该接口的情况
 

       5.总结

             1.该版权限控制在rest接口上,效果如上述所示。这只是简单的实例,根据具体的项目需要丰富表内容。

             2.前台调用后台提供接口,需先访问登录接口,获取bearer认证头和角色ID作为参数传入到每个接口。

             3.认证头为缓存实现为5分钟,避免了获取一次,永久访问的情况。

 

二、流程详解

         1.采用maven架构搭建整个工程,主要采用spring+mybatis配置后台,从数据库封装一个查询接口,提供一个restful

            具体代码略,会提供rest接口的自然懂……

                    rest接口步骤:                 测试工具:
                             1.dto                firefox插件(restClient/Httprest)
                             2.dao               secureCRT 后台查看工具(本地测试采用控制台)
                             3.daoimpl           
                             4.dto.xml
                             5.ws

            与一般的底层增删改查一致,就是ws层根据实际项目需要返回,一般返回json或者xml格式的数据

 

       2.搭建好之后,集成memcached,采用客户端为xmemcached(详见memcached客户端使用的三种方式)

      

       3.集成shiro

            1.web.xml中加入shiro过滤器,拦截rest下的所有url

            

	 <filter>
	    <filter-name>shiroFilter</filter-name>
	    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	    <init-param>
	        <param-name>targetFilterLifecycle</param-name>
	        <param-value>true</param-value>
	    </init-param>
	</filter>
	
	<filter-mapping>
	    <filter-name>shiroFilter</filter-name>
	    <url-pattern>/rest/*</url-pattern>
	</filter-mapping>

          2.把请求的url交给shiro之后,由于我们要把权限控制在接口上,shiro.xml相应变化;

             每次请求来交给一个自定义过滤器,除开登录的url,拦截web.xml中过来的所有请求。

 

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
			
		<property name="filters">
            <util:map>
                <entry key="custom" value-ref="customFilter"/>
            </util:map>
        </property>
        
		<property name="filterChainDefinitions">
			<value>
				/rest/login = anon
				/** = custom
			</value>
		</property>
	</bean>
	<!-- 自定义过滤器 -->
	<bean id="customFilter" class="com.sss.shiro.CustomFilter"/>

            

          3.请求交给自定义过滤器

                     1.  自定义过滤器继承AuthenticatingFilter,此时会强制重写createTokenonAccessDenied两个方法。

               A. createToken :表示创建一个用户身份验证的一个令牌,在其shiro底层有两个拦截器继承了AuthenticatingFilter分别是BasicHttpAuthenticationFilterFormAuthenticationFilter这两个同时实现了createToken方法,createToken方法里面是通过每次代入用户名和密码和把请求的requestresponse放入进去生成即可(需要了解的可以仔细看看源码)。我这里用这个令牌的目的就是替换底层实现的这一套,每次在登陆的接口里面设置,登陆成功之后随机生成一个UUID作为认证的bearer

 

	/***
	 * 创建一个令牌
	 *    每次请求的信息封装在token里面,在realm中的认证方法中获取和比对
	 */
	@Override
	protected AuthenticationToken createToken(ServletRequest request,
			ServletResponse response) throws Exception {
		String name = request.getParameter("name");
		String bearer = request.getParameter("bearer");
		String roleId = request.getParameter("roleId");
		return new CustomToken(name, bearer,roleId);
	} 

    认证的token中主要的一个部分bearer是在登录接口中放入的随机UUID

 

                        user.setPwd(encryptPwd);
			user.setIp(ip);
			String bearer = UUID.randomUUID().toString();
			user.setBearer(bearer);
			user.setRoleId(roleId);
			memcached.addCache("bearer", user, 5);
			memcached.addCache("permissionList", permissions, 1);

        这是登录接口返回的user 。 缓存中放入认证头bearer,其目的就是客户端和shiro的realm中的认证方法里拿到的realm进行比对。避免一次请求,永久访问。

       权限放入缓存,是方便查询,在shiro的realm中授权方法里面比对该登录的用户是否有访问该接口的权限,先从缓存里取,加快查询速度,缓存失效拿不到再通过

       roleId查询数据中比对之后放入缓存。

       

        B.onAccessDenied:表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。

      也是该自定义过滤器的入口,主要判断认证信息是否存在,存在即交给处理方法进行处理。

     

	@Override
	protected boolean onAccessDenied(ServletRequest request,
			ServletResponse response) throws Exception {
		logger.info("访问控制拦截器中传入参数:{}",request.getParameterMap());
		String bearer = request.getParameter("bearer");
		boolean isLogin = false;
		if (StringUtils.isNotEmpty(bearer)) {
			isLogin = executeLogin(request, response);
		}
		return isLogin;
	  }  

           B-1.此处处理涉及了一个executeLogin方法得到当前的用户,通过subject.login(token);交给realm中的认证方法来认证,由于错误信息不友好,自定义executeLogin方法  覆盖掉它。

           B-2.若认证失败给接口提示,若认证成功,通过boolean isPermitted = subject.isPermitted(httpRequest.getRequestURI());把当前访问的rest接口路径交给realm中的授权方法判断是否有该接口的访问权限。有访问权限出数据,没有就给提示。

           B-3.通过subject.login(token) 这里token就是自定义的token,通过createToken创建。通过shiro的realm中的认证方法可以知道,当前认证接受的token值为AuthenticationToken。所以我们这定义的token类就去实现它。属性若干,根据实际需要定义。

 

     public class CustomToken implements AuthenticationToken {

	private static final long serialVersionUID = 1L;

	private String username;
	private String roleId;
	private String bearer;
	private User user;
	
	public CustomToken(String username,String clientDigest,String roleId){
		this.bearer = clientDigest;
		this.username = username;
		this.roleId = roleId;
	}
	public CustomToken(User user){
		 this.user= user;
	}
	
           B-4.其中的roleId是需要的。

 

 

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {

		logger.info("enter---shiro的认证方法");
		CustomToken CustomToken = (CustomToken) token;
		String bearer = CustomToken.getBearer();
		String roleId = CustomToken.getRoleId();
		User user = null;
		try {
			user = (User) memcachedUtils.findCache("bearer");
		} catch (Exception e) {
			logger.debug("缓存读取认证头失败:{}", user);
			return null;
		}
		// 然后进行客户端消息摘要和服务器端消息摘要的匹配
		SimpleAuthenticationInfo aa = new SimpleAuthenticationInfo(roleId,
				user.getBearer(), getName());
		return aa;

	}
        此处主要从登陆接口中放入的缓存头,来获取,如果有比对认证(也可以在此处通过用户名比对一次密码),认证之后返回这个认证信息,带入orderId.

        认证通过之后,在执行方法里面判断是否有权限访问该url

 

        boolean isPermitted = subject.isPermitted(httpRequest.getRequestURI());
	if(!isPermitted){
	     sendChallenge(response, "该用户没有权限访问,请联系管理员用户",null);
             return false;
	}

     通过isPermitted进入到realm的授权方法

 

protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		// 先读取缓存数据,再通过roleId查询数据加入缓存
		//此处的授权参数就是接口带入的roleId,以便缓存失效时重新获取数据库中的权限集合
		logger.info("授权参数:{}", principals);
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		Set<String> permissions = new HashSet<>();
		try {
			if (memcachedUtils.findCache("permissionList") == null) {
				logger.debug("从数据库读取");
				//通过roleId来读取权限集合
				String roleId = principals.toString();
				Map<String, Object> whereMap = new HashMap<String, Object>();
				whereMap.put("roleId", roleId);
				List<Map<String, Object>> allPermissUrl = userDao
						.selectPermissionByName(whereMap);
				for (Map<String, Object> map : allPermissUrl) {
					permissions.add(dom4jReadXML(map.get("permission_name")
							.toString()));
				}
			} else {
				logger.debug("从缓存信息读取");
				//从缓存读权限集合
				ArrayList<String> permissionLists = (ArrayList) memcachedUtils
						.findCache("permissionList");
				for (String str : permissionLists) {
					permissions.add(dom4jReadXML(str));
				}
			}
			info.setStringPermissions(permissions);
		} catch (Exception e) {
			logger.debug("权限缓存放入失败");
			e.printStackTrace();
		}
		return info;
	}

        此处通过自己也有个疑问,shiro的认证和登录是两个独立的过程,但是此处的授权参数是认证方法第一个参数传入对应的属性roleId。(需要深入看看源码)

    如果登录接口的缓存放入的权限还未失效,直接比对,否则查库比对。

最后给出数据或者提示。

 

 

                  C.从上面两张图可以看到 shiro 提供了很多拦截器,实现这里可以继承很多不同的拦截器,onAccessDenied就是AccessControlFilter中的。

      继承AuthenticatingFilter主要是为了替换底层实现的这一套createToken

 

                D.最后每次访问返回出错的信息,同一由一个方法输出。这个方法在多个shiro的拦截器中实现,我们替换掉,通过接口转换成json格式输出。

	/***
	 * 认证失败,之后的提示
	 * 
	 */
	@Override
	protected boolean onLoginFailure(AuthenticationToken token,
			AuthenticationException e, ServletRequest request,
			ServletResponse response) {
		HttpServletRequest httpRequest = WebUtils.toHttp(request);
		
		try {
			String msg = "客户端[" + InetAddress.getLocalHost().getHostAddress().toString() + "]访问["
					+ httpRequest.getRequestURI() + "]认证错误.";
			sendChallenge(response, msg, null);
		} catch (UnknownHostException e1) {
			e1.printStackTrace();
		}
		return super.onLoginFailure(token, e, request, response);
	}

 


 三、总结

           1.主要流程也是先认证,后比对权限。认证的时候随机生成的UUID,缓存时间随需要设置。

           2.替换内部一套拦截器,按需要的逻辑简化认证授权

           3.缓存很重要

 

四、参考

          http://jinnianshilongnian.iteye.com/blog/2041909

 

 

 

 

 

  • 大小: 21.6 KB
  • 大小: 213.1 KB
  • 大小: 324.9 KB
  • 大小: 197.6 KB
  • 大小: 446.8 KB
  • 大小: 217.4 KB
分享到:
评论
1 楼 yihengvip 2014-12-26  
沙发

相关推荐

    ssm-shiro权限管理(二)

    在“ssm-shiro权限管理(二)”中,我们将深入探讨如何在Shiro的基础上进一步优化登录流程、实现缓存管理和动态权限分配。Shiro是一个强大且易用的Java安全框架,提供了认证、授权、会话管理和加密等功能,为应用...

    shiro权限管理案例加文档

    在这个“shiro权限管理案例加文档”中,我们很可能会找到关于如何在实际项目中应用Shiro进行权限控制的详细教程和实例。 **一、Shiro基础** Shiro的核心组件包括:Subject(主体)、Realms(域)、Cryptography...

    SSM+Shiro权限管理Demo

    SSM+Shiro权限管理Demo是一个综合性的项目实例,它结合了Spring、Spring MVC(SSM)和Apache Shiro框架来实现一个完善的权限控制体系。这个项目不仅涉及到后端的权限设计,还涵盖了前端页面的展示,使得用户界面与...

    shiro权限管理示例

    Apache Shiro是一个强大且易用的Java安全框架,它提供了认证、授权、加密和会话管理功能,可以非常方便地用于构建和强化应用程序的安全性。本示例将深入讲解Shiro在权限管理中的应用。 首先,我们要理解Shiro的核心...

    springboot-shiro权限管理系统.zip

    《SpringBoot-Shiro权限管理系统详解》 在现代的Web开发中,权限管理和用户认证是不可或缺的重要环节。SpringBoot作为一款轻量级的Java框架,以其快速开发、易于配置的特性深受开发者喜爱。Shiro则是Apache组织提供...

    管理系统系列--SpringBoot+Shiro权限管理系统脚手架.zip

    【SpringBoot+Shiro权限管理系统脚手架】是基于Spring Boot和Apache Shiro框架构建的高效、便捷的企业级权限管理解决方案。Spring Boot以其简洁的配置和快速开发的特点,已经成为Java Web开发的主流选择,而Shiro则...

    ssm-shiro权限管理(一)

    SSM-Shiro权限管理是Java Web开发中一种常见的权限控制框架集成方案,它结合了Spring、SpringMVC、MyBatis以及Apache Shiro这四个组件,实现了一个完整的权限管理系统。在本文中,我们将深入探讨如何将这四个组件...

    springboot-shiro-demo_mybatisplus_DEMO_shiro权限管理_

    本项目"springboot-shiro-demo_mybatisplus_DEMO_shiro权限管理_"结合了这三个技术,旨在实现一个高效且安全的权限管理系统。下面将详细介绍这些知识点。 **Spring Boot** Spring Boot是基于Spring框架的轻量级开发...

    shiro权限管理(一)

    在"Shiro权限管理(一)"这篇博文中,我们可能会探讨Shiro的基础概念和如何在项目中实现基本的权限控制。让我们深入了解一下Shiro的核心组件和使用方法。 1. **身份验证(Authentication)**: Shiro提供了处理...

    Springboot+shiro权限管理

    本文将深入探讨"Springboot+shiro权限管理"的主题,旨在提供最详尽、最清晰的理解路径。 首先,Spring Boot 是一个基于 Spring 框架的轻量级开发工具,它简化了初始化、配置以及运行Spring应用程序的过程。Spring ...

    spring boot+shiro 权限认证管理案例

    Spring Boot 和 Apache Shiro 的整合是企业级应用中常见的权限认证和安全管理方案。Spring Boot 提供了简化 Java 应用程序开发的框架,而 Shiro 是一个轻量级的安全框架,专注于身份验证、授权、会话管理和加密。...

    Shiro权限管理 的jar包 ,一些example ,shiro资料笔记与核心单词

    在本文中,我们将深入探讨Shiro权限管理的相关知识点,以及如何利用它来实现高效的安全控制。 1. **Shiro基础概念** - **身份验证(Authentication)**:确认用户身份的过程,通常涉及用户名和密码的校验。 - **...

    shiro权限管理类项目框架

    在这个"shiro权限管理类项目框架"中,我们将深入探讨 Shiro 如何帮助我们实现权限控制。 Shiro 的核心组件包括: 1. **认证**:这是验证用户身份的过程。在 Shiro 中,我们可以创建一个 `Subject` 对象代表当前...

    shiro权限管理实例

    在这个"shiro权限管理实例"中,我们可以通过学习和实践来深入理解Shiro如何在实际项目中处理用户权限控制。 首先,让我们从身份验证(Authentication)开始。在Shiro中,身份验证是指验证用户提供的身份信息是否...

    SpringMVC+Shiro权限管理.

    ### SpringMVC+Shiro权限管理系统详解 #### 权限管理概述 权限管理在软件开发中扮演着至关重要的角色,特别是在涉及多用户交互的应用场景下。通过合理的权限控制,可以确保不同用户仅能访问和操作他们被授权的功能...

    shiro权限管理(spring+mybatis+shiro)

    spring+mybatis+shiro整合。。。简单入门案例,maven项目

    移动互联网场景下服务端Shiro权限管理研究.pdf

    移动互联网场景下服务端Shiro权限管理研究 1. 背景介绍 在移动互联网时代,Web系统、App和微信小程序等多种形式的混合应用层出不穷。随之而来的是权限管理的复杂性显著增加。当前的系统权限管理存在授权方式复杂、...

    Go-Go语言版本的权限管理服务平台利用shiro权限管理设计思想

    Shiro的授权机制允许基于角色(Role-Based Access Control, RBAC)的权限管理,但在这个Go版本中,我们实现了更细粒度的控制,可以针对单个资源进行授权,超越了传统的RBAC模型。 3. **会话管理(Session ...

    shiro权限管理框架.pdf

    Shiro是一个开源的Java...在配置和使用Shiro进行权限管理时,需要对框架有一个全面的理解,包括上述提到的认证、授权、会话管理等核心概念,以及框架的架构细节,这样才能有效地利用Shiro构建出安全稳定的应用程序。

    Shiro权限管理示例(包括数据库结构)

    Apache Shiro是一个强大的Java安全框架,它提供了身份验证、授权(权限管理)、会话管理和加密服务。这个示例项目提供了一个完整的Shiro实现,特别强调了权限管理,并且结合了数据库来存储用户和角色信息。从提供的...

Global site tag (gtag.js) - Google Analytics