Springboot整合shiro:第二篇 用户授权注解方式实现


继上一篇 Springboot整合shiro:第一篇 用户验证完成了springboot整合shiro及shiro的用户验证功能,本篇是在第一篇的基础上完成用户授权功能(用户、角色、权限信息见第一篇)的

Shiro用户授权可以使用两种方式来完成:

  1. 采用注解的方式,如@RequiresRoles 、@RequiresPermissions等
  2. 配置自定义URL过滤器 (下一篇完成)

注解方式

完成用户授权的方法

在UserRealm中完成用户授权方法doGetAuthorizationInfo

/**
	 * 用户通过验证后,Shiro可通过该方法对登录用户进行授权 角色 或 权限, 只有先通过用户验证后才会走到用户授权这一步
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
		// 获取登录用户名
		String name = (String) principalCollection.getPrimaryPrincipal();
		/**
		 * 获取当前登录用户的权限和角色
		 */
		Set<String> privileges = userService.listPrivilege(name);
		Set<String> roles = userService.listRole(name);
		// Shiro配置授权 信息
		SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();
		/**
		 * 把通过service获取到的角色和权限放进去
		 */
		s.setStringPermissions(privileges);
		s.setRoles(roles);
		return s;
	}

配置DefaultAdvisorAutoProxyCreator

在Shiro配置类ShiroConfiguration中配置bean,这个bean配置一定得配置,不然注解方式授权会无效

@Bean
	public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
    
    
		DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		autoProxyCreator.setProxyTargetClass(true);
		return autoProxyCreator;
	}

编写查询角色、权限的代码

UserService中添加方法:

@Override
	public Set<String> listPrivilege(String name) {
    
    
		return userMapper.listPrivilege(name);
	}

	@Override
	public Set<String> listRole(String name) {
    
    
		return userMapper.listRole(name);
	}

UserServiceImpl中编写实现:

@Override
	public Set<String> listPrivilege(String name) {
    
    
		return userMapper.listPrivilege(name);
	}

	@Override
	public Set<String> listRole(String name) {
    
    
		return userMapper.listRole(name);
	}

UserMapper中添加接口:

/**
	 * 根据用户名查询对应的权限
	 * 
	 * @param name
	 * @return
	 */
	Set<String> listPrivilege(String name);

	/**
	 * 根据用户名查询对应的角色
	 * 
	 * @param name
	 * @return
	 */
	Set<String> listRole(String name);
	

UserMapper.xml添加查询SQL

<!-- 根据用户名查询权限 -->
	<select id="listPrivilege" parameterType="string"
		resultType="string">
		SELECT p.name FROM privilege p INNER JOIN role_privilege rp
		ON rp.privilege_id = p.id
		INNER JOIN roles r ON rp.role_id = r.id AND
		r.name = (SELECT
		r.name FROM roles r INNER JOIN user_role ur ON
		ur.role_id = r.id
		INNER
		JOIN users u ON u.id = ur.user_id AND u.name =
		#{name});
	</select>
	<!-- 根据用户名查询角色 -->
	<select id="listRole" parameterType="string" resultType="string">
		SELECT
		r.name FROM roles r INNER JOIN user_role ur ON ur.role_id = r.id
		INNER
		JOIN users u ON u.id = ur.user_id AND u.name = #{name};
	</select>

编写未授权异常处理类

这个地方需要主要一下的是:本来在ShrioConfiguration类中的shirFilter方法中可以直接配置 “未授权的跳转地址的”如注释掉的部分://未授权访问,跳转的地址setUnauthorizedUrl方法只针对部分过滤器有效,有些过滤器是无效的 // shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");,但是这里有点小坑的是,如果真这样配置是无法跳转的,
原因见:shiro无权限,不跳转到指定页面。setUnauthorizedUrl无效

@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    
    
		System.out.println("ShiroConfiguration.shirFilter()");
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面。
		shiroFilterFactoryBean.setLoginUrl("/notLogin");
		//未授权访问,跳转的地址setUnauthorizedUrl方法只针对部分过滤器有效,有些过滤器是无效的
//		shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 拦截器
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

		// 配置映射关系
		filterChainDefinitionMap.put("/login", "anon");
		filterChainDefinitionMap.put("/**", "authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

所以需要写一个异常处理类,来完成跳转

package com.xl.practice.springbootshiropractice.shiro;

import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;

@ControllerAdvice
public class PublicExceptionHandler {
    
    
	
	@ExceptionHandler({
    
    UnauthorizedException.class})
	public String processUnauthenticatedException(NativeWebRequest request,UnauthorizedException e) {
    
    
		
		return "redirect:unauthorized";
	}
}

Controller中添加相关方法

/**
	 * @description 获得工资报酬 
	 * @return
	 */
	@RequiresRoles("TEACHER")  //这个注解表示:该方法需要TEACHER这个角色才能访问
	@RequestMapping("/gainSalary")
	public String gainSalary() {
    
    
		return "请查收本月工资:6000 RMB";
	}
	
	/**
	 * 
	 * @return
	 */
	@RequiresPermissions("PLAY_GAME") // 这个注解表示:该方法需要PLAY_GAME这个权限才能访问
	@RequestMapping("/playGame")
	public String playGame() {
    
    
		return "正在越塔中。。。";
	}
	
	/**
	 *   角色不对或无权限跳转的地址
	 * @return
	 */
	@RequestMapping("/unauthorized")
	public String unauthorized() {
    
    
		return "。。。。。。。。角色不对,没有权限哦";
	}

验证

用户-角色-权限的关系参见第一篇:Springboot整合shiro:第一篇 用户验证

在这里插入图片描述

首先,验证@RequiresRoles

在TestController中添加的方法:

/**
	 * @description 获得工资报酬 
	 * @return
	 */
	@RequiresRoles("TEACHER")  //这个注解表示:该方法需要TEACHER这个角色才能访问
	@RequestMapping("/gainSalary")
	public String gainSalary() {
    
    
		return "请查收本月工资:6000 RMB";
	}

只有TEACHER这个角色可以访问,那么根据当前数据库的角色信息可得:苍老师 (111)可以访问,小炮同学 (666) 无法访问。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

@RequiresPermissions与@RequiresRoles类似,就不做验证了

注解方式的弊端

注解方式以硬编码的形式来授权,一旦权限发生变动就需要,修改代码,然后重新部署,这就比较麻烦,不灵活。

所以,使用“配置自定义URL过滤器 ”的方式会更好,见Springboot整合shiro:第三篇 用户授权-配置自定义URL过滤器 实现

本文源码:

https://github.com/michaelXu12/myrop/tree/master/springboot-shiro

参考文章:SHIRO系列教材 (九)- 在 SPRINGBOOT 中整合 SHIRO

猜你喜欢

转载自blog.csdn.net/qq_29025955/article/details/108774009