【SpringSecurity】三、访问授权

news2025/1/16 5:50:46

文章目录

  • 1、配置用户权限
  • 2、针对URL授权
  • 3、针对方法的授权

1、配置用户权限

继续上一章,给在内存中创建两个用户配置权限。配置权限有两种方式:

  • 配置roles
  • 配置authorities
//哪个写在后面哪个起作用
//角色变成权限后会加一个ROLE_前缀,比如ROLE_teacher
UserDetails user2 = User.builder()
        .username("thomas")
        .password(passwordEncoder().encode("123456"))
        .authorities("teacher:add","teacher:update")
        .roles("teacher")
        .build();
        
UserDetails user2 = User.builder()
        .username("thomas")
        .password(passwordEncoder().encode("123456"))
        .roles("teacher")
        .authorities("teacher:add","teacher:update")
        .build();


以上两种写法,顺序不同,获取当前登录用户时,得到的权限值也不一样。总结就是:

  • 如果给一个用户同时配置roles和authorities,哪个方法后面调用哪个起作用
  • 配置roles时,权限名会加上ROLE_

当然,从代码层来说,角色和权限并没太大区别,并特别是在Spring Security中。

2、针对URL授权

未做授权时,默认登录成功的用户可以访问所有资源(调任意一个接口),但有的接口只能允许管理员调用,因此,这里需要再实现授权功能。先看针对URL授权,即哪些权限可以访问哪些URL。新建配置类MyWebSecurityConfig,继承抽象类WebSecurityConfigurerAdapter,重写configure(HttpSecurity http)方法

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()  //授权请求
                .anyRequest()   //任何请求
                .denyAll();  //拒绝所有请求访问
                //.permitAll(); //允许所有请求
    }
}

在这里插入图片描述
放开登录认证页面:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()  //授权请求
                .anyRequest()   //任何请求
                .denyAll();  //拒绝所有请求访问
                //.permitAll(); //允许所有请求
        http.formLogin().permitAll();  //放开表单登录
    }
}

针对不同的url,要求拥有不同的权限才能访问,实现如下:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/student/**")
                .hasAnyAuthority("ROLE_student", "ROLE_teacher")   //有任一权限就能访问上面的url,形参是可变长字符串
                .mvcMatchers("/teacher/**")
                .hasAuthority("ROLE_teacher") //必须有这个权限才能访问上面的url
                .anyRequest() //任何请求
                .authenticated();  //都需要登录,即那些没有单独设置权限的url,仅需登录就能访问

        http.formLogin().permitAll();
    }
}

关于URL匹配,可选框架中的以下方法:

  • mvcMatchers() (优先)
  • regexMatchers()
  • antMatchers()

关于校验是否有对应的权限,框架中的方法可选:

  • hasAuthority() 是否有单个权限
  • hasRole()
  • hasAnyAuthority() 是否有其中任一个权限
  • hasAnyRole()

还可以.access()写表达式:

.mvcMatchers("/admin/**")
.access("hasRole('teacher') or hasAuthority('admin:query')")
//里面用单引号,省的转义

3、针对方法的授权

上面是URL级别的授权,接下来进行方法级别的权限控制。先写一个增删改查的简单代码,方便后面测试。

测试素材代码:

//新建教师接口
public interface TeacherService {
    String add();
    String update();
    String delete();
    String query();
}

//实现接口
@Service
@Slf4j
public class TeacherServiceImpl implements TeacherService {
    @Override
    public String add() {
        log.info("添加教师成功");
        return "添加教师成功";
    }

    @Override
    public String update() {
        log.info("修改教师成功");
        return "修改教师成功";
    }

    @Override
    public String delete() {
        log.info("删除教师成功");
        return "删除教师成功";
    }

    @Override
    public String query() {
        log.info("查询教师成功");
        return "查询教师成功";
    }
}

简单补充下controller:

@RestController
@RequestMapping("/teacher")
public class TeacherController {
    @Resource
    private TeacherService teacherService;

    @GetMapping("/query")
    public String queryInfo() {
        return teacherService.query();
    }

    @GetMapping("/add")
    public String addInfo() {
        return teacherService.add();
    }

    @GetMapping("/update")
    public String updateInfo() {
        return teacherService.update();
    }

    @GetMapping("/delete")
    public String deleteInfo() {
        return teacherService.delete();
    }
}

配置类中新建三个测试用户在内存中:

@Configuration
public class MySecurityUserConfig {
    @Bean
    public UserDetailsService userDetailService() {
        UserDetails user1 = User.builder()
                .username("liu")
                .password(passwordEncoder().encode("123456"))
                .roles("student")
                .build();

        UserDetails user2 = User.builder()
                .username("Mr.liu")
                .password(passwordEncoder().encode("123456"))
                .roles("teacher")
                .build();
        UserDetails user3 = User.builder()
                .username("admin")
                .password(passwordEncoder().encode("123456"))
                .authorities("teacher:add", "teacher:update")
                .build();
        //创建两个用户
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        userDetailsManager.createUser(user1);
        userDetailsManager.createUser(user2);
        return userDetailsManager;
    }

    /*
     * 从 Spring5 开始,强制要求密码要加密
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        //使用加密算法对密码进行加密
        return new BCryptPasswordEncoder();
    }

}

Web安全配置适配器类:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
		//任何访问均需要认证
        http.authorizeRequests().anyRequest().authenticated();
        http.formLogin().permitAll();
    }
}

进行方法级别的控制

首先,加上启动全局方法安全的注解 @EnableGlobalMethodSecurity(prePostEnabled = true)

//@Configuration
//@EnableGlobalMethodSecurity注解中有@Configuration注解,所以这里注掉了就
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //任何访问均需要认证
        http.authorizeRequests().anyRequest().authenticated();
        //登录放行
        http.formLogin().permitAll();
    }
}

@EnableGlobalMethodSecurity(prePostEnabled = true)中的prePostEnabled是预授权和后授权,预授权即访问前判断有无权限,后授权则是方法执行完以后才判断是否有权限,后授权的使用场景比较少。接下来修改要控制访问的方法,使用 前置授权注解@PreAuthorize

@Service
@Slf4j
public class TeacherServiceImpl implements TeacherService {
    @Override
    @PreAuthorize("hasAuthority('teacher:add') OR hasRole('teacher')")
    public String add() {
        log.info("添加教师成功");
        return "添加教师成功";
    }

    @Override
    @PreAuthorize("hasAuthority('teacher:update')")
    public String update() {
        log.info("修改教师成功");
        return "修改教师成功";
    }

    @Override
    @PreAuthorize("hasAuthority('teacher:delete')")
    public String delete() {
        log.info("删除教师成功");
        return "删除教师成功";
    }

    @Override
    @PreAuthorize("hasRole('teacher')")
    public String query() {
        log.info("查询教师成功");
        return "查询教师成功";
    }
}

此时,登录有不同权限的不同角色,其只能访问对应有权限的方法。

在这里插入图片描述

注意,这里控制的是对方法的访问,仅仅是限制对方法的访问。

	@GetMapping("/delete")
    public String deleteInfo() {
        return teacherService.delete();
    }

改为:

	@GetMapping("/delete")
    public String deleteInfo() {
    	int a = 10
    	log.info("进入了TeacherController,a={}" , a);
        return teacherService.delete();
    }

登录学生账户,访问delete接口,此时结果仍然403,但控制台可以看到在到达被限制权限的方法前的代码是可以访问的:

在这里插入图片描述

当然,@PreAuthorize注解也可以写在Controller中的方法上,此时上面的int a = 10自然就访问不到了。

小总结:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flask狼书笔记 | 03_模板

文章目录 3 模板3.1 模板基本使用3.2 模板结构组织3.3 模板进阶 3 模板 模板(template):包含固定内容和动态部分的可重用文件。Jinja2模板引擎可用于任何纯文本文件。 3.1 模板基本使用 HTML实体:https://dev.w3.org/html5/htm…

启动Vue项目踩坑记录

前言 在启动自己的Vue项目时&#xff0c;遇到一些报错&#xff0c;当时很懵&#xff0c;解决了以后豁然开朗&#xff0c;特写此博客记录一下。 一、<template>里多加了个div标签 [vite] Internal server error: At least one <template> or <script> is req…

EureKa快速入门

EureKa快速入门 远程调用的问题 多个服务有多个端口&#xff0c;这样的话服务有多个&#xff0c;硬编码不太适合 eureKa的作用 将service的所有服务的端口全部记录下来 想要的话 直接从注册中心查询对于所有服务 每隔一段时间需要想eureKa发送请求 保证服务还存活 动手实践 …

odoo安装启动遇到的问题

问题&#xff1a;在第一次加载odoo配置文件的时候&#xff0c;启动失败 方法&#xff1a; 1、先检查odoo.conf的内容&#xff0c;尤其是路径 [options] ; This is the password that allows database operations: ; admin_passwd admin db_host 127.0.0.1 db_port 5432 d…

kotlin协程flow任务意外结束未emit数据retryWhen onEmpty(5)

kotlin协程flow任务意外结束未emit数据retryWhen onEmpty&#xff08;5&#xff09; import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeoutOrNullfun main(args: Array<String&…

【Java】基础练习(九)

1.结婚 创建一个Person类&#xff0c;如下: public class Person{private String name;private Character gender;private Integer age;private Boolean marry;// 省略 getter / settter / 构造 / toString / hashCode / equals }有一个类CAB&#xff0c;有一个canMarry方…

SpringBoot(二)

###SpringBoot原理分析 ###SpringBoot监控 ###SpringBoot项目部署 #SpringBoot自动配置 Condition&#xff1a;&#xff08;条件&#xff09; Condition是在Spring4.0增加的条件判断功能&#xff0c;通过这个功能可以实现选择性的创建Bean操作 SpringBoot是如何知道要创建…

如何在服务器上用kaggle下载数据集

S1 服务器上安装kaggle cli工具 pip install --user kaggleS2 服务器上创建kaggle目录 mkdir ~/.kaggleS3 进入kaggle账户创建token 生成token 点击右上角头像&#xff0c;选择setting 点击create new token 进入你的浏览器下载页&#xff0c;可以看到有了一个kaggle.jso…

快速了解什么是Cookie

&#x1f600;前言 本篇博文是关于Web 开发会话技术 -Cookie的介绍&#xff0c;希望你能够喜欢&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的…

Elasticsearch 入门安装

1.Elasticsearch 是什么 The Elastic Stack, 包括 Elasticsearch、 Kibana、 Beats 和 Logstash&#xff08;也称为 ELK Stack&#xff09;。能够安全可靠地获取任何来源、任何格式的数据&#xff0c;然后实时地对数据进行搜索、分析和可视化。 Elaticsearch&#xff0c;简称为…

0822|C++day2 引用+函数重载

一、左值引用(reference) 如果想要实现两个数据的交换&#xff0c;值传递不能交换实参&#xff0c;地址传递可以交换实参&#xff0c;会额外开辟空间 【1】概念 引用其实就是给变量起了一个别名&#xff0c;孙悟空(齐天大圣)C对C的一个最重要的扩充 【2】定义 数据类型 &am…

链表oj(复制随机链表)、栈和队列oj(循环队列)

文章目录 1.链表oj 2.栈和队列oj 文章内容 1.链表oj 1. 给定一个链表&#xff0c;每个结点包含一个额外增加的随机指针&#xff0c;该指针可以指向链表中的任何结点 或空结点。要求返回这个链表的深度拷贝。力扣 该题不仅要求复制链表&#xff0c;而且每个节点有两个指针域…

【C语言】自定义类型(结构体+枚举+联合)

一、结构体 1、结构体类型的声明 &#xff08;1&#xff09;结构的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 &#xff08;2&#xff09;结构的声明 举例&#xff1a; // 形容一名学生 struct Stu {char name[20];…

7.elasticsearch同步工具-logstah

1.logstah Logstash 是一个用于数据处理和转换的开源工具&#xff0c;它可以将来自不同源头的数据收集、转换、过滤&#xff0c;并将其发送到不同的目标。Logstash 是 ELK&#xff08;Elasticsearch、Logstash 和 Kibana&#xff09;技术栈的一部分&#xff0c;通常与 Elastics…

JVM理论知识

一、JVM内存结构 java的内存模型主要分为5个部分&#xff0c;分别是&#xff1a;JVM堆、JVM栈、本地栈、方法区还有程序计数器&#xff0c;他们的用途分别是&#xff1a; JVM堆&#xff1a;新建的对象都会放在这里&#xff0c;他是JVM中所占内存最大的区域。他又分为新生区还…

无处不在的拉普拉斯——边缘,斑点,金字塔

作为拿破仑的老师和“法国牛顿”&#xff0c;拉普拉斯在数学和天体力学中贡献颇多&#xff0c;但其实在图像处理中也会发现拉普拉斯的身影。怎么它又可以用来检测斑点&#xff0c;又可以检测边缘&#xff0c;又可以金字塔重建&#xff0c;还可以平滑&#xff0c;还可以增强细节…

redis 6个节点(3主3从),始终一个节点不能启动

redis节点&#xff0c;始终有一个节点不能启动起来 1.修改了配置文件 protected-mode no&#xff0c;重启 修改了配置文件 protected-mode no&#xff0c;重启redis问题依然存在 2、查看/var/log/message的redis日志 Aug 21 07:40:33 redisMaster kernel: Out of memory: K…

Vue2-Vuex概念及使用场景、Vuex环境搭建、Vuex工作原理、Vuex配置项、Vuex模块化及命名空间

&#x1f954;&#xff1a;山不向我走来&#xff0c;我便向它走去 更多Vue知识请点击——Vue.js VUE2-Day11 理解Vuex1、Vuex是什么2、什么时候使用Vuex Vuex环境搭建1、安装vuex2、创建store文件3、main.js引入store Vuex的工作原理1、原理图2、用案例解释工作原理3、注意点 V…

linux之《进程》

文章目录 进程基础pcb状态优先级 进程的调度常见的调度算法 进程的通信方式 进程基础 pcb 操作系统在创建进程时&#xff0c;会给进程分配一块PCB&#xff08;process control block 进程控制块&#xff09;&#xff0c;对应linux上就是task_struct结构体&#xff0c;PCB里面…

非root用户下安装OpenSSL

1.OpenSSL下载 https://www.openssl.org/source/ 2.将下载好的压缩包上传至linux 3.解压压缩包 tar -xvf openssl-3.0.7.tar.gz 4.创建openssl安装目录 mkdir /home/openssl 5.进入安装包解压后的目录 cd /home/openssl-3.0.7.tar.gz 6.安装openssl&#xff0c;注意命令是…