Shiro 基于权限授权的简单应用与授权注解

上篇文章有必要看一下:Shiro 基于角色授权的简单应用与权限过滤器配置含义

一、基于权限授权的简单应用

数据库:

     

    用户admin, 只拥有角色 admin 和 user 与访问  /admin/userlist 的权限资源,如果 pid 为1和2,则两者都可访问。

1、spring.xml 在配置 shiro 的过滤器上,配置权限控制的拦截规则:

        注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的

    <!-- 配置shiro的一些拦截规则,id必须和web.xml中的 shiro 拦截器名一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    	<!-- Shiro的核心安全接口,这个属性是必须的 -->  
		<property name="securityManager" ref="securityManager" />
		<!-- 身份认证失败,则跳转到登录页面的配置 --> 
		<property name="loginUrl" value="/login" />  
		<!-- 登录成功后的页面 -->
		<property name="successUrl" value="/admin/index" />  
		<!-- 权限认证失败,则跳转到指定页面 --> 
		<property name="unauthorizedUrl"  value="/unauthorized" />  <!-- 登录后访问没有权限的页面后跳转的页面 -->
		<!-- Shiro连接约束配置,即过滤链的定义 -->  
		<property name="filterChainDefinitions">
			<value>
				<!-- 注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的
				 url = 拦截规则(anon为匿名,authc为要登录后,才能访问,logout登出过滤) -->
				/login = anon
				/logout = logout
				/admin/userlist = perms[userlist]
				/admin/addUser = perms[addUser]
				/admin/** = authc    
				/**= anon  
			</value>
		</property> 
	</bean>

2、自定义 ShiroRealm类的继承 AuthorizingRealm 类:

      登录认证方法不用修改,授权认证方法做相应修改

	/**
	 * 在 shiro 中专门做授权认证的方法
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {		
		//1 从参数 principals 中获取当前登录成功后的用户信息
		User user = principals.oneByType(User.class);
		//2 根据第一步中的用户信息,获取角色信息(若用户信息包含角色/权限信息,直接取出,若没有,从数据库中获取)
		Set<String> roles = RoleMapper.getRolesByUserid(user.getId());
		// 通过用户关联的role信息,获取角色关联的 permisssion信息
		Set<String> permissions = permissionMapper.getPermissionsByUserid(user.getId());
		
		//3 把获取到的登录用户关联的角色和权限资源信息注入到返回的SimpleAuthorizationInfo对象中
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addRoles(roles);
		info.addStringPermissions(permissions);
		return info;
	}

PermissionMapper 方法:

	<select id="getPermissionsByUserid" resultType="String">
		select
			p.pname
		from 
			 t_user u,t_role r,t_user_role ur,t_permission p,t_role_permission rp
		where
			u.id=ur.userid and ur.roleid=r.id and r.id=rp.rid and rp.pid=p.id
			and u.id = #{userid}
	</select>

3、登录访问项目

     结果和数据库分析一致

二、Shiro 的授权注解 

1、5个授权注解

        @RequiresRoles(value = {"admin","user"},logical = Logical.AND)

        当前Subject必须拥有所有指定的角色时,才能访问被该注解标注的方法。如果当Subject不同时拥有所有指定角色,则方法不会执行还会抛出AuthorizationException异常

        @RequiresPermissions(value = {"userlist","userlist2"},logical=Logical.OR)

        当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法。如果当前Subject不具有这样的权限,则方法不会被执行

        认证通过后接受 Shiro 授权检查,授权验证时,需要先判断当前角色是否拥有该权限,只有授权通过,才可以访问受保护 URL 对应的资源,否则跳转到“未经授权页面”。

        @RequiresAuthentication

        用于表明当前用户需是经过认证的用户。使用该注解标注的类/实例/方法在访问或调用时,要求当前Subject 必须在当前的session 中被认证通过才能被访问或调用。即 Subjec.isAuthenticated()返回 true

        @RequiresUser

        该注解需要当前的Subject 是一个应用程序用户才能被注解的类/实例/方法访问或调用。一个“应用程序用户”被定义为一个拥有已知身份,或在当前session 中由于通过验证被确认,或者在之前session 中的'RememberMe'服务被记住。

        @RequiresGuest

        使用该注解标注的类/实例/方法在访问或调用时,当前Subject可以是“gust”身份,不需要经过认证或者在原先的session中存在记录,客身份

     

2、使用方法

        Shiro 的授权注解处理是有内定的处理顺序的,如果有多个注解的话,前面的通过了会继续检查后面的,若不通过则直接返回,处理顺序依次为(与实际声明顺序无关)

RequiresRoles 
RequiresPermissions 
RequiresAuthentication 
RequiresUser 
RequiresGuest

例如:你如果同时声明了 RequiresRoles 和 RequiresPermissions 注解,那就要求拥有此角色的同时还得拥有相应的权限。

三、基于权限授权的简单注解应用

  使用注解 实现 第一点 的功能

1、spring.xml 在配置 shiro 的过滤器上

      取消配置权限控制的拦截规则,

      添加一个SimpleMappingExceptionResolver异常处理。

    <!-- 配置shiro的一些拦截规则,id必须和web.xml中的 shiro 拦截器名一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    	<!-- Shiro的核心安全接口,这个属性是必须的 -->  
		<property name="securityManager" ref="securityManager" />
		<!-- 身份认证失败,则跳转到登录页面的配置 --> 
		<property name="loginUrl" value="/login" />  
		<!-- 登录成功后的页面 -->
		<property name="successUrl" value="/admin/index" />  
		<!-- 权限认证失败,则跳转到指定页面 --> 
		<property name="unauthorizedUrl"  value="/unauthorized" />  <!-- 登录后访问没有权限的页面后跳转的页面 -->
		
	</bean>
	<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionMappings">
			<props>
				<prop key="org.apache.shiro.authz.UnauthorizedException">unauthorized</prop>
				<prop key="org.apache.shiro.authz.UnauthenticatedException">login</prop>
			</props>
		</property>
	</bean>

2、自定义 ShiroRealm类的继承 AuthorizingRealm 类:和第一点相同处理

3、action 类中进行注解授权:

	@RequiresGuest
	@GetMapping(value= {"/","/login"})
	public String login(Model model, HttpSession session) {
		//生成一组16位随机数
		int hashCodeValue = UUID.randomUUID().hashCode();
		if(hashCodeValue < 0) hashCodeValue = -hashCodeValue;
		String uuidSalt = String.format("%016d",hashCodeValue);//左边补0,16位,进制(d,x)
		
		//把uuid盐值,同时保存在前后端
		model.addAttribute("uuidSalt", uuidSalt);
		session.setAttribute("uuidSalt", uuidSalt);
		return "login";
	}
	
	@RequiresGuest
	@PostMapping("/login")
	public String login(User user, HttpSession session) {
		//使用 shiro 登录验证
		//1 认证的核心组件:获取 Subject 对象
		Subject subject = SecurityUtils.getSubject();
				
		//2 将登陆表单封装成 token 对象
		UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPazzword());
		try {
			//3 让 shiro 框架进行登录验证:
			subject.login(token);
		} catch (Exception e) {
			e.printStackTrace();
			return "loginError";
		}
		return "redirect:/admin/index";
	}
	
	@RequiresAuthentication
	@GetMapping("/admin/index")
	public String admin(Model model) {
		return "admin/index";
	}
	
	@RequiresPermissions(value = {"userlist","userlist2"},logical=Logical.OR)
	@GetMapping("/admin/userlist")
	public String userlist() {
		return "admin/userlist";
	}
	
	@RequiresPermissions(value = {"addUser"})
	@GetMapping("/admin/addUser")
	public String addUser() {
		return "admin/addUser";
	}
	
	@GetMapping("/unauthorized")
	public String unauthorized() {
		return "unauthorized";
	}
	
	/**
	 * shrio 使用注解之后,需要自己实现退出
	 */
	@GetMapping("/logout")
	public String logout() {
		SecurityUtils.getSubject().logout(); //实现退出
		return "redirect:/login";
	}

4、登录访问项目:

   结果和上面一致

注意:使用注解后的2个问题

1、退出登录需要自己实现(SecurityUtils.getSubject().logout();)。

2、没有登录认证访问无访问权限的页面后的跳转要自己配置实现(添加一个SimpleMappingExceptionResolver异常处理)。

不处理这两个问题会出现这个:

 

 

 5、测试一下同时声明了 RequiresRoles 和 RequiresPermissions 注解

	@RequiresRoles(value = {"admin2","user"},logical=Logical.AND)
	@RequiresPermissions(value = {"userlist","userlist2"},logical=Logical.OR)
	@GetMapping("/admin/userlist")
	public String userlist() {
		System.out.println("admin");
		return "admin/userlist";
	}

    用户 admin,拥有 admin 和 user 角色,userlist  权限资源,所以上面会跳转到 无访问权限 页面。

    把 RequiresRoles 中 admin2 改为 admin 时, 认证通过,能够访问 /admin/userlist  权限资源。

end ~

 

 

猜你喜欢

转载自blog.csdn.net/qq_42402854/article/details/89494783