首页 > 编程语言 >Java研学-Shiro安全框架(五)

Java研学-Shiro安全框架(五)

时间:2024-08-28 10:53:16浏览次数:13  
标签:info Java return 研学 new 权限 public Shiro

七 SpringBoot集成Shiro鉴权

1 Shiro 鉴权三种方式

  编程式 通过写 if/else 授权代码块完成

Subject subject = SecurityUtils.getSubject();
if(subject.hasRole("hr")) {
	//有权限
} else {
	//无权限
}

  注解式 通过在controller的方法上放置相应的注解完成(shiro已经做好了,直接贴就行)

@RequiresRoles("hr") 
@RequiresPermissions("user:create") 
// 设置多个权限是否同时需要,或者只有其中一种即可
// @RequiresPermissions(value={"user:create","user:delete"},logical=logical.OR) 
public void addUser(User user) {
    //有权限
}

  JSP标签(shiro自带) 、Freemarker的标签(第三方) 、ThymeLeaf的标签(第三方)在页面通过相应的标签完成,ThymeLeaf标签文档,通过标签完成有权限显示,无权限不显示。

<a shiro:hasRole="administrator" href="admin.html">Administer the system</a>
<a shiro:hasPermission="user:create" href="createUser.html">Create a new User</a>

2 Shiro 拦截方法流程

在这里插入图片描述

3 支持注解鉴权配置

  需要ShiroConfig中配置Shiro注解通知器Bean(当看到注解后通知SecurityManager进行权限认证),与支持CGLIB的Bean

// 开启Shiro注解通知器
// Qualifier(起别名)此处 SecurityManager 可能报错,因为lang包是自动导入的
// 所以此处的 SecurityManager 是lang包下的,我们需要的是Shiro包下的 SecurityManager 可使用acap.xx.xx.xx.SecurityManager 这种方式,
// 或者使用之前定义的安全管理器类型 DefaultWebSecurityManager 防止自动导包
// public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
//        DefaultWebSecurityManager securityManager){}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
        @Qualifier("securityManager") SecurityManager securityManager)
{
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
}
// 设置支持CGlib代理
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    advisorAutoProxyCreator.setProxyTargetClass(true);
    return advisorAutoProxyCreator;
}

4 完善Realm的授权方法

  在Apache Shiro中,SimpleAuthorizationInfo 并不直接与 Subject 关联。相反,SimpleAuthorizationInfo 是用于封装授权信息(如角色和权限)的,这些信息随后会被存储在 SecurityManager 的上下文中,以便在需要时与 Subject 进行关联和检查

//授权相关
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
	// 获取登录用户
    Employee employee = (Employee)principals.getPrimaryPrincipal();
    // 封装授权信息类
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //根据用户的id查询该用户拥有的角色编码
    List<Role> roles = roleService.queryByEmployeeId(employee.getId());
    for(Role role:roles){
        info.addRole(role.getSn());
    }
    //根据用户的id查询该用户拥有的权限表达式
    List<String> permissions = permissionService.queryByEmployeeId(employee.getId());
    info.addStringPermissions(permissions);
    return info;
}

5 完善自定义异常 – 无权限异常

@ControllerAdvice
public class ExceptionControllerAdvice {
    // 自定义异常(向让用户看到的)
    @ExceptionHandler(BusinessException.class)
    public String handlerException(BusinessException e, Model model, HandlerMethod method, HttpServletResponse response){
        // 异常也分为页面异常和 ajax 请求的异常。
        if(method.hasMethodAnnotation(ResponseBody.class)){
            // ajax 请求
            response.setContentType("application/json;charset=utf-8");
            try {
                response.getWriter().write(new ObjectMapper().writeValueAsString(new JsonResult(false,e.getMessage())));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return null;
        } else{
            // 页面请求
            model.addAttribute("errorMsg",e.getMessage());
            return "common/error";
        }
    }

    // 系统异常(不想让用户看到的)
    @ExceptionHandler(Exception.class)
    public String handlerException(Exception e, Model model, HandlerMethod method, HttpServletResponse response){
        // 异常也分为页面异常和 ajax 请求的异常。
        if(method.hasMethodAnnotation(ResponseBody.class)){
            // ajax 请求
            response.setContentType("application/json;charset=utf-8");
            try {
                response.getWriter().write(new ObjectMapper().writeValueAsString(new JsonResult(false,"系统繁忙,请联系管理员")));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return null;
        } else{
            // 页面请求
            model.addAttribute("errorMsg","系统繁忙,请联系管理员");
            return "common/error";
        }
    }

    // 没有权限异常
    @ExceptionHandler(UnauthorizedException.class)
    public String handlerException(UnauthorizedException e, Model model, HandlerMethod method, HttpServletResponse response){
        // 异常也分为页面异常和 ajax 请求的异常。
        if(method.hasMethodAnnotation(ResponseBody.class)){
            // ajax 请求
            response.setContentType("application/json;charset=utf-8");
            try {
                response.getWriter().write(new ObjectMapper().writeValueAsString(new JsonResult(false,"您还没有权限访问,请联系管理员")));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return null;
        } else{
            // 页面请求
            model.addAttribute("errorMsg","您还没有权限访问,请联系管理员");
            return "common/nopermission";
        }
    }
}

6 超级管理员权限

  超级管理员并没有配置任务的角色和权限会被拦截。所以需要在授权代码中做特殊的处理

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    Employee employee = (Employee)principals.getPrimaryPrincipal();
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    if(employee.isAdmin()){
        //如果是超级管理员,给管理员赋所有的权限
        List<Role> roles = roleService.listAll();
        for(Role role:roles){
            info.addRole(role.getSn());
        }
        //使用通配符表示拥有所有的权限
        info.addStringPermission("*:*");
    }else{
        //根据用户的id查询该用户拥有的角色编码
        List<Role> roles = roleService.queryByEmployeeId(employee.getId());
        for(Role role:roles){
            info.addRole(role.getSn());
        }
        //根据用户的id查询该用户拥有的权限表达式
        List<String> permissions = permissionService.queryByEmployeeId(employee.getId());
        info.addStringPermissions(permissions);
    }
    return info;
}

7 ShringBoot集成Shiro实现注解式鉴权功能步骤

  1. 在需要权限控制的控制器方法上面贴上注解。
    • @RequiresPermissions() ==> 需要权限控制
    • @RequiresRoles() ==> 需要角色控制
  2. 由于 Shiro 中使用的是 AOP 的方式对方法进行拦截控制,所以我们需要在配置文件中配置注解通知器,配置支持CGLIB。
  3. 完善 Realm 中授权逻辑
    • 根据用户名查询当前用户信息。
    • 根据用户信息查询用户的权限集合和角色集合。
  4. 对于超级管理员应该拥有一切的角色和权限。(角色必须通过遍历才能添加,权限可以使用通配符)

8 编程式鉴权

  这种方式允许开发者根据业务需求自定义鉴权逻辑,具有较高的灵活性和可定制性。(注解式必须抛异常,编程式可不抛)

@RequestMapping("/list")
public String list(Model model, QueryObject qo) {
    Subject subject = SecurityUtils.getSubject();
    PageInfo<Department> pageInfo = null;
    if(subject.isPermitted("department:list")){
        pageInfo = departmentService.query(qo);
    }else{
        pageInfo = new PageInfo<>(Collections.EMPTY_LIST);
    }
    model.addAttribute("pageInfo", pageInfo);
    return "department/list";
}

9 标签式鉴权

  ① 需要依赖(可以不是thymeleaf)

<!-- thymeleaf模板引擎和shiro框架的整合 -->
<dependency>
	<groupId>com.github.theborakompanioni</groupId>
	<artifactId>thymeleaf-extras-shiro</artifactId>
	<version>${thymeleaf.extras.shiro.version}</version>
</dependency>

  ② 配置Shiro集成ThymeLeaf标签支持(ShiroConfig中添加Bean)

// thymeleaf模板引擎和shiro框架的整合
@Bean
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}

  ③ 页面中添加约束头

<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

  ④ 使用标签

<a href="#" class="btn btn-success btn-input" style="margin: 10px" shiro:hasPermission="department:saveOrUpdate">
    <span class="glyphicon glyphicon-plus"></span> 添加
</a>

标签:info,Java,return,研学,new,权限,public,Shiro
From: https://blog.csdn.net/zhlyxx/article/details/140329307

相关文章

  • JavaScript 程序寻找通过 2 个点的线(Program to find line passing through 2 Points)
              在数学和计算机科学中,找到通过两个点的线的方程是一个基础问题。假设我们有两个点 P1​(x1​,y1​) 和 P2​(x2​,y2​),我们想要找到通过这两个点的直线方程。直线方程的形式直线的方程通常表示为 y=mx+b,其中 m 是斜率,b 是 y 轴截距。计算斜率......
  • java计算机毕业设计校园跑腿服务平台(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在快速发展的数字时代,校园生活日益多元化与快节奏,学生们对于便捷高效的生活服务需求日益增长。传统的校园服务模式已难以满足学生群体对于时间管理......
  • java计算机毕业设计疫情防控信息管理系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景:在全球化日益加深的今天,突发公共卫生事件如疫情的爆发,对各国社会经济及民众生活构成了前所未有的挑战。疫情防控成为各国政府及社会各界关注的焦点。......
  • Java计算机毕业设计社区智能诊疗服务系统(开题+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和人口老龄化趋势的加剧,医疗资源分布不均、就医难、看病贵等问题日益凸显。传统诊疗模式面临巨大挑战,患者往往需要长时间排队......
  • java计算机毕业设计智能汽车租赁系统的设计与实现(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着科技的飞速发展和城市化进程的加速,智能出行已成为现代社会的重要趋势。传统汽车租赁行业面临着效率低下、管理复杂、用户体验不佳等挑战。随着物......
  • Java--枚举类型
    目录定义声明枚举类EnumMapEnumSet使用场景定义枚举是一个特殊的类,一般表示一组常量,比如一年的4个季节,一年的12月份,方向的东南西北等声明使用enum关键字来定义,各个常量使用逗号,来分割例如:enumColor{RED,GREEN,BLUE}publicclassTest{//执行输出结果publ......
  • Java学习笔记9-数据类型的转化
    一.显示转化在Java中,数据类型的转换主要分为两种:自动类型转换(也称为隐式类型转换)和强制类型转换(也称为显式类型转换)。1.自动类型转换(隐式类型转换)自动类型转换是指在赋值或运算过程中,较小的数据类型自动转换为较大的数据类型。Java编译器会自动进行这种转换,不需要程序员显式指......
  • Java--泛型
    目录什么是泛型泛型的作用泛型的特性泛型的使用泛型类泛型接口泛型方法泛型通配符什么是泛型泛型是JavaSE5中引入的一个新特性,它提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。简单来说,泛型是一种参数化类型,它可以将类型(类、接口、枚举等)作为参数传......
  • Java学习笔记10-运算符
    Java运算符是用于执行各种数学、逻辑和位运算的符号。Java中的运算符可以分为以下几类:一、算术运算符用于执行基本的数学运算,如加、减、乘、除和取模。常用的算术运算符包括+、-、*、/和%。算数运算符详解Java中的算术运算符包括加、减、乘、除、取模等,下面分别详细介绍。1.1......
  • Java泛型
    Java泛型是Java语言的一个重要特性,它允许你在编译时指定类型参数,从而编写更加灵活和可重用的代码。Java泛型的概念Java泛型是在JDK5.0中引入的,它允许你在声明类、接口和方法时使用类型参数。类型参数可以是你定义的任何标识符,通常使用大写字母如E,T,K,V等表示。使用泛型......