六:Day06_Spring Security02

一、访问控制(授权)

1. 基于资源访问控制

  • 查询用户的权限。

  • 访问资源时判断用户是否具有指定的权限。

1.1 修改UserServiceImpl
@Service
public class UserServiceImpl implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private MenuMapper menuMapper;

    /**
     * @param username  前端登录时提交的用户名
     * @return          用户的认证信息,要求必须为UserDetails接口的实现类
     * @throws UsernameNotFoundException  用户名没有找到时的异常
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        User myUser = userMapper.selectOne(wrapper);
        if (myUser == null){
            throw new UsernameNotFoundException("用户名不存在");
        }
        
        //查询用户拥有的权限
        List<Menu> menus = menuMapper.selectByUserId(myUser.getId());
        ArrayList<GrantedAuthority> list = new ArrayList<>();
        menus.forEach(menu -> {
            //获取的权限为null时,将null添加到SimpleGrantedAuthority会出现
            //A granted authority textual representation is required异常信息
            String permission = menu.getPermission();
            if (permission != null && permission!=""){
                list.add(new SimpleGrantedAuthority(permission));
            }
        });

        //参数一:用户名  参数二:密码  参数三:权限
        /*
        * org.springframework.security.core.userdetails.User为UserDetails接口的实现类。
        * 也可以自定义的User实现UserDetail接口提供对应的属性。
        * */
        org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(
                myUser.getUsername(), myUser.getPassword(), list);
        return user;
    }
}
1.2 修改配置类
	//请求授权设置。
        /*
        * antMatchers():对指定的请求url进行控制
        * permitAll():允许访问
        * anyRequest():任意一个请求url的控制
        * authenticated():认证后便可以访问
        * hasAuthority():存在指定的权限可以访问
        * hasAnyRole(String ...):存在指定的任意一个权限可以访问
        * */
        http.authorizeRequests()
                .antMatchers("/login.html").permitAll()  //login.html不需要被认证
                .antMatchers("/stu/select").hasAuthority("stu:select") //需要有指定的权限
                .antMatchers("/stu/insert").hasAuthority("stu:insert") //需要有指定的权限
                .antMatchers("/stu/update").hasAuthority("stu:update") //需要有指定的权限
                .antMatchers("/stu/del").hasAuthority("stu:del")       //需要有指定的权限
                .anyRequest().authenticated();                       //其它任意的请求都必须被认证,必须认证(登录成功)后就可以直接访问

2. 基于角色访问控制

2.1 修改UserServiceImpl

官网要求:角色前必须添加 ROLE_ 前缀,角色才会生效。例如:ROLE_admin。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService, UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private RoleMapper roleMapper;

    /**
     * @param username 前端登录时提交的用户名
     * @return 用户的认证信息,要求必须为UserDetails接口的实现类
     * @throws UsernameNotFoundException 用户名没有找到时的异常
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        User myUser = userMapper.selectOne(wrapper);
        if (myUser == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        /*
         * org.springframework.security.core.userdetails.User为UserDetails接口的实现类。
         * 也可以自定义的User实现UserDetail接口提供对应的属性。
         * */
        //查询用户拥有的权限
        List<Menu> menus = menuMapper.selectByUserId(myUser.getId());
        ArrayList<GrantedAuthority> list = new ArrayList<>();
        menus.forEach(menu -> {
            //获取的权限为null时,将null添加到SimpleGrantedAuthority会出现
            //A granted authority textual representation is required异常信息
            String permission = menu.getPermission();
            if (permission != null && permission != "") {
                list.add(new SimpleGrantedAuthority(permission));
            }
        });
        
        //查询用户所有角色
        List<Role> roles = roleMapper.selectByUserId(myUser.getId());
        roles.forEach(role -> {
            list.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        });

        //参数一:用户名  参数二:密码  参数三:权限
        org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(
                myUser.getUsername(), myUser.getPassword(), list);
        return user;
    }
}
2.2 修改配置类
 //请求授权设置。
        /*
        * antMatchers():对指定的请求url进行控制
        * permitAll():允许访问
        * anyRequest():任意一个请求url的控制
        * authenticated():认证后便可以访问
        * hasAuthority():存在指定的权限可以访问
        * hasAnyRole(String ...):存在指定的任意一个权限可以访问
        * hasRole():存在指定的角色可以访问
        * hasAnyRole():存在指定的任意一个角色可以访问
        * */
        http.authorizeRequests()
                .antMatchers("/login.html").permitAll()  //login.html不需要被认证
                .antMatchers("/stu/select").hasAuthority("stu:select") //需要有指定的权限
                .antMatchers("/stu/insert").hasAuthority("stu:insert") //需要有指定的权限
                .antMatchers("/stu/update").hasRole("管理员")          //需要有指定的角色
                .antMatchers("/stu/del").hasRole("管理员")             //需要有指定的角色
                .anyRequest().authenticated();                        //其它任意的请求都必须被认证,必须认证(登录成功)后就可以直接访问

二、基于注解的访问控制

在Spring Security中提供了一些访问控制的注解。这些注解都是默认是都不可用的,需要通过@EnableGlobalMethodSecurity进行开启后使用

这些注解可以写到Service接口或方法上,也可以写到Controller或Controller的方法上。通常情况下都是写在控制器方法上的,控制接口URL是否允许被访问

1. 注解介绍

1.1 @PreAuthorize
  • @PreAuthorize:表示访问方法或类在执行之前先判断权限,大多情况下都是使用这个注解。

  • 注意:必须在启动类@EnableGlobalMethodSecurity中设置prePostEnabled = true

1.2 @PostAuthorize
  • @PostAuthorize:表示方法或类执行结束后判断权限,此注解很少被使用到。

2 . 修改配置类

  • 配置类中不再需要配置基于资源和基于角色的权限控制。

3. 修改启动器

  • 在启动类中通过@EnableGlobalMethodSecurity开启@PreAuthorize注解。

  • @EnableGlobalMethodSecurity(prePostEnabled = true)

4. 修改控制器

  • 在控制器方法上添加@PreAuthorize。

@RestController
@RequestMapping("stu")
public class StudentController {

    @RequestMapping("insert")
    @PreAuthorize("hasAuthority('stu:select')")
    public String insert(){
        return "添加学生";
    }

    @RequestMapping("update")
    @PreAuthorize("hasAuthority('stu:update')")
    public String update(){
        return "修改学生";
    }

    @RequestMapping("del")
    @PreAuthorize("hasRole('ROLE_管理员')")
    public String del(){
        return "删除学生";
    }

    @RequestMapping("select")
    @PreAuthorize("hasRole('ROLE_管理员')")
    public String select(){
        return "查询学生";
    }
}

三、自定义403处理方案

在Spring Security 的 自定义配置类( WebSecurityConfigurerAdapter )中使用HttpSecurity 提供的 exceptionHandling() 方法用来处理异常。该方法构造出 ExceptionHandlingConfigurer 异常处理配置类。该配置类提供了两个实用接口:

  1. AuthenticationEntryPoint 该类用来统一处理 AuthenticationException 异常

  2. AccessDeniedHandler 该类用来统一处理 AccessDeniedException 异常

1. 新建类

新建类实现AccessDeniedHandler。

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
        httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        out.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员!\"}");
        out.flush();
     }
}

2. 修改配置类

配置类中重点添加异常处理器。设置访问受限后交给哪个对象进行处理。

@Autowired
private AccessDeniedHandler accessDeniedHandler;
//异常处理
http.exceptionHandling()
        .accessDeniedHandler(accessDeniedHandler);

四、Spring Security整合Thymeleaf使用

在项目中添加此jar包的依赖和thymeleaf的依赖。

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    <version>3.0.4.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

html添加命名空间。

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">

1. 获取属性

根据源码得出下面属性:

  1. name:登录账号名称

  2. principal:登录主体,在自定义登录逻辑中是UserDetails

  3. credentials:凭证

  4. authorities:权限和角色

  5. details:实际上是WebAuthenticationDetails的实例。可以获取remoteAddress(客户端ip)和sessionId(当前sessionId)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    登录账号:<span sec:authentication="name">123</span><br/>
    登录账号:<span sec:authentication="principal.username">456</span><br/>
    凭证:<span sec:authentication="credentials">456</span><br/>
    权限和角色:<span sec:authentication="authorities">456</span><br/>
    客户端地址:<span sec:authentication="details.remoteAddress">456</span><br/>
    sessionId:<span sec:authentication="details.sessionId">456</span><br/>
</body>
</html>

2. 权限判断

如果用户具有指定的权限,则显示对应的内容;如果表达式不成立,则不显示对应的元素。

通过权限判断:
<button sec:authorize="hasAuthority('stu:insert')">新增</button>
<button sec:authorize="hasAuthority('stu:delete')">删除</button>
<button sec:authorize="hasAuthority('stu:update')">修改</button>
<button sec:authorize="hasAuthority('stu:select')">查看</button>
<br/>
通过角色判断:
<button sec:authorize="hasRole('管理员')">新增</button>
<button sec:authorize="hasRole('管理员')">删除</button>
<button sec:authorize="hasRole('管理员')">修改</button>
<button sec:authorize="hasRole('管理员')">查看</button>

五、Spring Security中CSRF

1. CSRF

CSRF英文全称叫做: cross-site request forgery,翻译过来叫做跨站请求伪造。spring security默认情况下是开启了csrf保护的。

CSRF 是致击者通过一些技术手段欺骗用户的浏览器,去访问一个用户曾经认证过的网站并执行恶意请求,例如发送邮件、发消息、甚至财产操作(如转账和购买商品)。由于客户端(浏览器)已经在该网站中认证过了,所以该网站会认为是真正用户在操作而执行请求(实际上并非用户的本意)。

2. Spring Security中CSRF

从Spring Security4开始CSRF防护默认开启。默认会拦截请求,以防止CSRF攻击应用程序处理。默认情况下会启用 CSRF 保护,,SpringSecurity CSRF 会针对 PATCH,POST,PUT 和 DELETE 方法进行防护。要求访问时携带参数名为_csrf值为token(token在服务端产生)的内容,如果token和服务端的token匹配成功,则正常访问。

注意,这里面不包括GET、HEAD、TRACE、OPTIONS请求,这些请求还是会存在这种问题的。

3. Spring Security中CSRF原理

  1. 当服务器加载登录页面,先生成csrf对象,并放入作用域中,key为_csrf。

  2. 用户在提交登录表单时,会携带csrf的token。如果客户端的token和服务器的token匹配说明是自己的客户端,否则无法继续执行。

  3. 用户退出的时候,必须发起POST请求,且和登录时一样,携带csrf的令牌。

4. 实现  

4.1 login.html

在项目resources下新建templates文件夹,并在文件夹中新建login.html页面。form表单中的第一行是必须存在的否则无法正常登录。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action = "/login" method="post">
	<input type="hidden" th:value="${_csrf.token}" name="_csrf" th:if="${_csrf}"/>
    用户名:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    <input type="submit" value="登录"/>
</form>
</body>
4.2 修改配置类

在配置类中注释掉CSRF防护失效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/243610.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS数组与它的42个方法

前言 数组在js中作为一个非常重要的类型之一&#xff0c;在我们对数据处理&#xff0c;存储数据&#xff0c;条件渲染的时候经常会用到&#xff0c;所以随着ES的不断更新&#xff0c;数组的方法也是越来越多&#xff0c;也让我们使用数组对数据操作的时候&#xff0c;越来越简…

Python中的继承:概念、用法与示例

目录 一、引言 二、继承的概念 三、继承的用法 1、继承父类的属性和方法 2、添加新的属性和方法 3、覆盖父类的方法 四、示例代码展示 五、继承中的多态性 六、继承中的封装和抽象 七、继承中的多重继承 总结 一、引言 面向对象编程&#xff08;OOP&#xff09;是一…

构建VREP和MATLAB联合仿真实验平台,控制机械臂末端按照固定轨迹移动

构建VREP和MATLAB联合仿真实验平台&#xff0c;控制机械臂末端按照固定轨迹移动。主要工作如下&#xff1a; &#xff08;1&#xff09;solidworks构建机械臂模型&#xff1b; &#xff08;2&#xff09;将solidworks中构建的模型导入VREP中建立机械臂的多体动力学模型&#xf…

10 个顶级 iPhone 数据恢复软件工具评测

很多事情都可能导致 iPhone 数据丢失&#xff1a;iOS 更新失败、越狱错误、解锁问题等。如果您遇到类似情况并且想要访问您的文件&#xff0c;通常最好的解决方案是使用数据恢复工具。由于研究市场上可用的工具可能会花费您大量的时间&#xff08;在尝试从 iPhone 恢复数据时&a…

二、Java基础语法

day02 - Java基础语法 1. 注释 ​ 注释是对代码的解释和说明文字。 Java中的注释分为三种&#xff1a; 单行注释&#xff1a; // 这是单行注释文字多行注释&#xff1a; /* 这是多行注释文字 这是多行注释文字 这是多行注释文字 */ 注意&#xff1a;多行注释不能嵌套使用…

Java 入门第四篇 集合

Java 入门第四篇 集合 一&#xff0c;什么是集合 在Java中&#xff0c;集合&#xff08;Collection&#xff09;是一种用于存储和操作一组对象的容器类。它提供了一系列的方法和功能&#xff0c;用于方便地管理和操作对象的集合。集合框架是Java中非常重要和常用的一部分&…

番茄病虫害检测系统:融合感受野注意力卷积(RFAConv)改进YOLOv8

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 番茄是全球重要的蔬菜作物之一&#xff0c;具有广泛的经济和营养价值。然而&#xff0c;番茄病虫害的严重威胁导致了产量和质量的损失。因此&#xff0c;开发一种…

hive聚合函数之排序

1 全局排序&#xff08;Order By&#xff09; Order By&#xff1a;全局排序&#xff0c;只有一个Reduce。 (1&#xff09;.使用Order By子句排序 asc&#xff08;ascend&#xff09;&#xff1a;升序&#xff08;默认&#xff09; desc&#xff08;descend&#xff09;&#…

C#- 代理模式(静态)

与装饰器模式类似&#xff0c;只继承接口&#xff1b; 示例代码&#xff1a; interface IStudent {public void GetInfo(); } class Student : IStudent {public void GetInfo(){Console.WriteLine("上小学中。。。");} } class ProxyStudent : IStudent {private …

纸质表格扫描转Excel的利器,让您省钱省劲

将纸质表格扫描到电脑Excel上是一种快捷而高效的数字化处理方法&#xff0c;使得数据可以方便地进行编辑、分析和共享。本文将介绍几种常用的方法来完成这项任务。 第一种方法是使用扫描仪。现代扫描仪具备较高的分辨率和颜色还原能力&#xff0c;可以将纸质表格转化为高质量的…

操作系统原理-作业三-存储器

某页式虚拟存储管理系统中&#xff0c;页面大小为 2KB &#xff0c;某一进程分配到的内存块数为 3 &#xff0c;并按下列地址顺序引用内存单元&#xff1a; 2531 、 6632 、 4140 、 3584 、 2892 、 5743 、 1700 、 2148 、 6940、 4345 、 3209 、 0732 、 6202 、 4541 。…

SAP ABAP 使用cl_md_bp_maintain=>maintain更新BP税号CN0的数据,更新结果都会变成CN5类型问题处理

SAP ABAP 使用cl_md_bp_maintain>maintain更新BP税号CN0的数据&#xff0c;更新结果都会变成CN5类型&#xff0c;CN1类型一切正常。 1、BP税号 2、跟踪方法中代码 查看底层逻辑&#xff0c;发现CN0都被强制替换成CN5了&#xff0c;BP GUI界面还能正常使用CN0. 查询NOTES&a…

机器学习:从概念到应用

机器学习&#xff1a;从概念到应用 一、引言 随着科技的飞速发展&#xff0c;人工智能已经渗透到我们生活的方方面面。作为人工智能领域的一个重要分支&#xff0c;机器学习正在改变我们的世界。它通过让计算机从数据中学习&#xff0c;实现自我优化和改进&#xff0c;为各行…

JS轮询任务查询订单退款状态

出现问题&#xff1a; 因为订单的支付不是普通的微信支付&#xff0c;是第三方支付&#xff0c;而且由于该三方支付自己内部设置的一些情况&#xff0c;导致退款的时候&#xff0c;发起了退款申请&#xff0c;但是会在15~20秒左右&#xff0c;才会返回结果&#xff0c;不像微信…

ISCTF2023 Reverse方向 WP

文章目录 ReversecrackmeEasyRebabyReeasy_z3FloweyRSAeasy_flower_teamfx_rez3_revengeWHERE Reverse crackme 、 加了UPX壳&#xff0c;可以看到EP Section处UPX标识被修改了 用WinHex修改 之后UPX脱壳 得到flag。 EasyRe 逆向一下&#xff0c;先逆序&#xff0c;再做一些…

台阶仪在大型基板应用有哪些

探针式轮廓仪&#xff08;台阶仪&#xff09;是一种用于测量物体表面轮廓和形状的仪器。在大型基板应用中&#xff0c;它可能被用于检测和分析半导体器件、平板显示屏、光伏电池板等大尺寸基板上的微小结构和形状。这样的测量对于确保生产质量、提高制造效率和优化工艺非常重要…

cfa一级考生复习经验分享系列(三)

从总成绩可以看出&#xff0c;位于90%水平之上&#xff0c;且置信区间全体均高于90%线。 从各科目成绩可以看出&#xff0c;所有科目均位于90%线上或高于90%线&#xff0c;其中&#xff0c;另类与衍生、公司金额、经济学、权益投资、固定收益、财报分析表现较好&#xff0c;目测…

张驰课堂:在线六西格玛认证,成就个人职业发展

随着数字化学习平台的兴起&#xff0c;六西格玛的学习方式更加灵活。以下是线上学习平台与传统面授培训的对比&#xff1a; 线上学习平台&#xff1a; 灵活性&#xff1a;学员可以根据自己的时间安排自学&#xff0c;不受地点限制。 成本效益&#xff1a;通常在线课程费用较低…

MySQL中的时间函数整理汇总

1.获取当前时间 -- 获取当前时间 SELECT NOW(); -- 获取当前日期 SELECT CURDATE(); -- 获取当前时分秒 SELECT CURTIME(); 2.获取对应日期对应的年/月/日/月份名/星期数 -- 返回对应日期对应的年/月/日/月份名/星期数 select year(now())as 年,month(now())as 月,day(now())…

迅速理解什么是通信前置机

通信前置机设在两个通信对象之间&#xff0c;是实质性的物理服务器&#xff0c;适应不同通信协议或数据格式之间的相互转换。 前置机的作用&#xff1a; 隔离——隔离客户端与服务端&#xff0c;保障后端安全减负——处理非核心业务&#xff0c;分担后端服务器压力&#xff0…
最新文章