概述
SpringBoot-Shiro权限控制(2019.12.13)
在《Spring-Boot-shiro用户认证》中,我们通过继承AuthorizingRealm抽象类实现了doGetAuthenticationInfo()
方法完成了用户认证操作。接下来继续实现doGetAuthorizationInfo()
方法完成Shiro的权限控制功能。
授权也称为访问控制,是管理资源访问的过程。即根据不同用户的权限判断其是否有访问相应资源的权限。在Shiro中,权限控制有三个核心的元素:权限,角色和用户。(也称为权限3要素)
库的模型分为 : 用户表 角色表 权限表 (3者都是多对多关系通过中间表关联)
创建了五张表:用户表USER、角色表ROLE、用户角色关联表USER_ROLE、权限表PERMISSION和权限角色关联表ROLE_PERMISSION。用户love角色为admin,用户tester角色为test。admin角色拥有用户的所有权限(user:user,user:add,user:delete),而test角色只拥有用户的查看权限(user:user)。密码都是321,没经过Shiro提供的MD5加密。
1. Dao层
创建两个实体类,对应用户角色表Role和用户权限表Permission:
@Data
public class Role implements Serializable {
private static final long serialVersionUID = -66L;
private Integer id;
private String name;
private String memo;
}
-----------------------------------------------------------------------------
@Data
public class Permission implements Serializable {
private static final long serialVersionUID = -66L;
private Integer id;
/**
* 权限路径
*/
private String url;
/**
* 权限名称
*/
private String name;
}
创建两个dao接口,分别根据用户名查询用户拥有所有角色和用户拥有的所有权限:
UserRoleMapper.java
@Mapper
public interface UserRoleMapper {
/**
* 根据用户名查询用户拥有所有角色
*
* @param username
* @return java.util.List<com.zhihao.entity.Role>
* @author: zhihao
* @date: 2019/12/13
*/
List<Role> findRoleByUserName(String username);
}
UserRoleMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.zhihao.dao.UserRoleMapper">
<select id="findRoleByUserName" resultType="com.zhihao.entity.Role">
SELECT ro.* FROM `user` u
LEFT JOIN user_role uro ON u.id=uro.user_id
RIGHT JOIN role ro ON ro.id = uro.rid WHERE u.username = #{username}
</select>
</mapper>
UserPermissionMapper.java
@Mapper
public interface UserPermissionMapper {
/**
* 根据用户名 查询出该用户拥有的所有权限
*
* @param username 用户名
* @return java.util.List<com.zhihao.entity.Permission>
* @author: zhihao
* @date: 2019/12/13
* {@link #}
*/
List<Permission> findPermissionByUserName(String username);
}
UserPermissionMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.zhihao.dao.UserPermissionMapper">
<select id="findPermissionByUserName" resultType="com.zhihao.entity.Permission">
SELECT per.* FROM `permission` per
LEFT JOIN role__permission rope ON per.id=rope.pid
LEFT JOIN role ro ON ro.id=rope.rid
LEFT JOIN user_role uro ON uro.rid=ro.id
LEFT JOIN `user` u ON u.id=uro.user_id WHERE u.username = #{username};
</select>
</mapper>
2.对ShiroRealm.java
进行改造。
在Shiro中,用户角色和权限的获取是在ShiroRealm的doGetAuthorizationInfo()
方法中实现的,所以接下来手动实现该方法:
/**
* 获取用户角色和权限
*
* @param principal
* @return org.apache.shiro.authz.AuthorizationInfo
* @author: zhihao
* @date: 2019/12/13
* {@link #}
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
//通过shiro工具获取登录后的user对象,获取到用户名
User user = (User) SecurityUtils.getSubject().getPrincipal();
String username = user.getUsername();
//创建授权对象进行封装角色和权限信息进去进行返回 注意不是SimpleAuthenticationInfo
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取用户角色集
List<Role> roleList = roleService.findRoleByUserName(username);
Set<String> roleSet = new HashSet<>();
for (Role role : roleList) {
roleSet.add(role.getName());
}
System.out.println("用户拥有的角色>>>"+roleSet);
//添加角色进角色授权
info.setRoles(roleSet);
List<Permission> permissionList = permissionService.findPermissionByUserName(username);
Set<String> permissionSet = new HashSet<>();
for (Permission permission : permissionList) {
permissionSet.add(permission.getName());
}
System.out.println("用户拥有的权限>>>"+permissionSet);
//添加权限进权限授权
info.setStringPermissions(permissionSet);
return info;
}
//..下面是之前的登录认证
在上述代码中,我们通过方法获取了当前登录用户的角色和权限集,然后保存到SimpleAuthorizationInfo对象中,并返回给Shiro,这样Shiro中就存储了当前用户的角色和权限信息了。
3. 对ShiroConfig.java进行改造配置。
要使用权限相关的注解必须要在配置中开启注解的使用,需要在ShiroConfig
中添加如下配置:
/**
* 开启shiro认证注解
*
* @param securityManager
* @return AuthorizationAttributeSourceAdvisor
* @author: zhihao
* @date: 2019/12/13
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
Shiro为我们提供了一些和权限相关的注解,如下所示:
// 表示当前Subject已经通过login进行了身份验证;即Subject.isAuthenticated()返回true。
@RequiresAuthentication
// 表示当前Subject已经身份验证或者通过记住我登录的。
@RequiresUser
// 表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。
@RequiresGuest
// 表示当前Subject需要角色admin和user。
@RequiresRoles(value={"admin", "user"}, logical= Logical.AND)
// 表示当前Subject需要权限user:a或user:b。
@RequiresPermissions (value={"user:a", "user:b"}, logical= Logical.OR)
4. 编写一个权限控制的UserController
来测试权限
@RestController
public class UserController {
/**
* 模拟从数据库获取了全部用户
*
* @return java.lang.String
* @author: zhihao
* @date: 2019/12/13
*/
@RequiresPermissions(value = "user:user") //使用shiro权限注解标明,只能拥有这个user:user权限的用户访问
@RequestMapping("/list")
public String getUserList(){
String userList ="拥有获取全部用户的权限 ``user:user``";
return userList;
}
@RequiresPermissions(value = "user:add")
@RequestMapping("/add")
public String addUser(){
String userList ="拥有添加用户权限 ``user:add``";
return userList;
}
@RequiresPermissions(value = "user:delete")
@RequestMapping("/delete")
public String deleteUser(){
String userList ="拥有删除用户权限 ``user:delete``";
return userList;
}
}
5. 在LoginController中添加一个/403跳转:
@GetMapping("/403")
public ModelAndView forbid() {
ModelAndView view = new ModelAndView();
view.setViewName("403");
return view;
}
6. 测试没有权限用户后端报AuthorizationException异常,
在测试中发现使用没有权限的用户访问后台抛出了异常:org.apache.shiro.authz.AuthorizationException: Not authorized to invoke method:…异常!!!
本以为在ShiroConfig中配置了shiroFilterFactoryBean.setUnauthorizedUrl("/403");
,没有权限的访问会自动重定向到/403,结果证明并不是这样。后来研究发现,该设置只对filterChain起作用,比如在filterChain中设置了filterChainDefinitionMap.put("/user/update", "perms[user:update]");
,如果用户没有user:update
权限,那么当其访问/user/update
的时候,页面会被重定向到/403。
对应以上问题可以有2种解决方法:
第一种: 定义一个全局异常处理进行处理:
@ControllerAdvice
@Order(value = Ordered.HIGHEST_PRECEDENCE) //最高精度,抛出的异常符合这个异常就进来
public class GlobalExceptionHandler {
@ExceptionHandler(value = AuthorizationException.class)
public String handleAuthorizationException() {
return "403";
}
}
第二种在配置类中配置个异常解析器
/**
* 异常解析器
*
* @return org.springframework.web.servlet.handler.SimpleMappingExceptionResolver
* @author: zhihao
* @date: 2019/12/13
* {@link #}
*/
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
//拦截到AuthorizationException 就跳转到resources资源下的 如果带文件夹需要加上文件夹: /xxx/403模板页面
properties.setProperty("AuthorizationException", "/403");
resolver.setExceptionMappings(properties);
return resolver;
}
最后发现无权限访问后正常到403页面了!
扩展资料:
建表语句: 在项目代码中
项目代码(点击打开)
最后
以上就是务实花生为你收集整理的SpringBoot-Shiro权限控制( 3 )SpringBoot-Shiro权限控制(2019.12.13)的全部内容,希望文章能够帮你解决SpringBoot-Shiro权限控制( 3 )SpringBoot-Shiro权限控制(2019.12.13)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复