【Spring Security】 入门实战

news2024/11/28 1:54:47

文章目录

  • 一、基本概念
  • 二、Spring Security第一个程序
  • 三、Spring Security没有生效
  • 四、修改默认账号密码(appliction.yml)
  • 五、修改默认账号密码(配置类)
  • 六、Spring Security的三个configure方法
  • 七、Spring Security的三种身份的验证

一、基本概念

单点登录

  • 什么叫做单点登录呢。就是在一个多应用系统中,只要在其中一个系统上登录之后,不需要在其它系统上登录也可以访问其内容。
  • 举个例子,京东那么复杂的系统肯定不会是单体结构,必然是微服务架构,比如订单功能是一个系统,交易是一个系统…那么我在下订单的时候登录了,付钱难道还需要再登录一次吗,如果是这样,用户体验也太差了吧。
  • 实现的流程就是我在下单的时候系统发现我没登录就让我登录,登录完了之后系统返回给我一个Token,就类似于身份证的东西;然后我想去付钱的时候就把Token再传到交易系统中,然后交易系统验证一下Token就知道是谁了,就不需要再让我登录一次。

JWT(JSON Web Token)
Token的生成与解密
在这里插入图片描述
RSA(非对称加密算法)
从上面的例子中可以看出,JWT在加密解密的时候都用到了同一个密钥 “ robod666 ”,这将会带来一个弊端,如果被黑客知道了密钥的内容,那么他就可以去伪造Token了。所以为了安全,我们可以使用非对称加密算法RSA。
在这里插入图片描述

二、Spring Security第一个程序

Spring Security导入依赖就能生效了。

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

查看Controller层结果

@RestController
public class UserController {
    @Autowired
    UserMapper userMapper;

    @RequestMapping("/user/select/{id}")
    public User list(@PathVariable("id") int id){
        return userMapper.queryUserById(id);
    }
}

启动项目,默认账号是user,密码在输出控制信息中
在这里插入图片描述

在浏览器中访问localhost:8080/user/selet/2,会自动跳转到localhost:8080/login
在这里插入图片描述

输入账号密码,跳转到我们原来请求的内容localhost:8080/user/selet/2
在这里插入图片描述

三、Spring Security没有生效

Spring Security在导入依赖之后就能生效,并且会使用一些默认配置。但是有时候导入依赖之后访问页面,也没有跳转到指定验证页面,这就是Spring Security没有生效。

这是因为,你在pom.xml中导入了依赖包,等于告诉maven要导入Spring Security依赖,但是不等于已经导入了Spring Securtiy,因为maven可能还没来得及导入,你就已经启动项目了。我们可以通过查看External Libraries这里,看看Spring Security是否已经导入成功。
在这里插入图片描述

四、修改默认账号密码(appliction.yml)

application.yml配置文件中修改默认账号密码
在这里插入图片描述

启动项目,在浏览器中访问localhost:8080/user/selet/2,会自动跳转到localhost:8080/login,账号是nicky,密码在123
在这里插入图片描述
输入账号密码,跳转到我们原来请求的内容localhost:8080/user/selet/2
在这里插入图片描述

五、修改默认账号密码(配置类)

也可以新建Spring Security配置类,注意Spring Security5.2.1版本,配置密码要用BCryptPasswordEncoder加密,不过登录还是明文,Spring Security不同版本各有差别,详情配置还是参考官方文档

@Configuration  // 设置为配置类,变成Spring Bean
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {    //auth.inMemoryAuthentication()
        auth.inMemoryAuthentication()
                .withUser("nicky")
                .password(bcryptPasswordEncoder().encode("123456"))
                .roles("admin")
            .and()
                .withUser("rocky")
                .password(bcryptPasswordEncoder().encode("123456"))
                .roles("admin");
    }
    @Bean
    public PasswordEncoder bcryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

启动项目,在浏览器中访问localhost:8080/user/selet/2,会自动跳转到localhost:8080/login,账号是nicky,密码在123
在这里插入图片描述
输入账号密码,跳转到我们原来请求的内容localhost:8080/user/selet/2
在这里插入图片描述

六、Spring Security的三个configure方法

Spring Security通过继承WebSecurityConfigurationAdapter这个类,可以选择实现该类中的三个重载的configure方法

configure(AuthenticationManagerBuilder auth):用来记录账号,密码,角色信息。

AuthenticationManagerBuilder allows 
    public void configure(AuthenticationManagerBuilder auth) {
        auth
            .inMemoryAuthentication()
            .withUser("user")
            .password("password")
            .roles("USER")
        .and()
            .withUser("admin")
            .password("password")
            .roles("ADMIN","USER");
}

configure(HttpSecurity http):(授权)配置 URL 访问权限,对应用户的权限

protected void configure(HttpSecurity http) throws Exception {
    http
    	//任何请求都必须经过身份验证
        .authorizeUrls()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .anyRequest().authenticated();

configure(WebSecurity):一般用于配置忽略掉的 URL 地址,一般用于js,css,图片等静态资源

public void configure(WebSecurity web) throws Exception {
    web
    	 //web.ignoring() 用来配置忽略掉的 URL 地址,一般用于静态文件
        .ignoring()
        .antMatchers("/resources/**");
}

七、Spring Security的三种身份的验证

1. 默认身份验证

在pom.xml文件映入SpringSecutrity依赖启动器,启动项目,访问文章列表页面时,出现默认的登录页,需要用默认用户名:user,密码源于控制台输出,也就是最基础的登录

2. 内存身份验证
自定义用户名和密码(用户名和密码是写在代码内,不好维护)

@Configuration  // 设置为配置类,变成Spring Bean
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {    
        auth.inMemoryAuthentication()
                .withUser("nicky").password(bcryptPasswordEncoder().encode("123456")).roles("admin")
            	.and()
                .withUser("rocky").password(bcryptPasswordEncoder().encode("123456")).roles("admin");
    }
    
    @Bean
    public PasswordEncoder bcryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();//开启运行iframe嵌套页面

        //任何请求都必须经过身份验证
        http.authorizeRequests()
                .anyRequest().authenticated();

		 http.authorizeRequests()
                .antMatchers("/vip/vip0/**").hasRole("vip0")
                .antMatchers("/vip/vip1/**").hasRole("vip1")
                .antMatchers("/vip/vip2/**").hasRole("vip2")
                .antMatchers("/vip/vip3/**").hasRole("vip3");


        //开启表单验证
        http.formLogin()
                .and()
                .formLogin()//开启表单验证
                .loginPage("/toLogin")//跳转到自定义的登录页面
                .usernameParameter("name")//自定义表单的用户名的name,默认为username
                .passwordParameter("pwd")//自定义表单的密码的name,默认为password
                .loginProcessingUrl("/doLogin")//表单请求的地址,一般与form的action属性一致
                .successForwardUrl("/index")//登录成功后跳转的页面(重定向)
                .failureForwardUrl("/toLogin")//登录失败后跳转的页面(重定向)
                .and()
                .logout()//开启注销功能
                .logoutSuccessUrl("/toLogin")//注销后跳转到哪一个页面
                .logoutUrl("/logout") // 配置注销登录请求URL为"/logout"(默认也就是 /logout)
                .clearAuthentication(true) // 清除身份认证信息
                .invalidateHttpSession(true) //使Http会话无效
                .permitAll() // 允许访问登录表单、登录接口
                .and().csrf().disable(); // 关闭csrf
    }
}

3. 数据库方式校验
实现WebSecurityConfigurerAdapter类:将身份校验方式改变为数据库方式校验,即使用UserDetailsService

/*开启安全管理配置*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsServiceImpl userDetailsService;

    /*自定义身份认证*/
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /*1. 密码编译器*/
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        /*2.使用UserDetails进行身份认证*/
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
    }

	/*自定义用户权限*/
	@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll()  // 表示放行“/”访问
                .antMatchers("/admin/**").hasAuthority("admin")		// 表示admin才能访问/admin/**
                .antMatchers("/common/**").hasAuthority("common")	// 表示common可以访问/commom/**
                .and()
                .formLogin();
    }
}

实现UserDetailsService类:该类只有 loadUserByUsername 一个接口方法, 用于通过用户名获取用户数据. 返回 UserDetails 对象, 表示用户的核心信息 (用户名, 用户密码, 权限等信息).

注意:其实UserDetailsService就是一个Service层的类,没有大不了的,我们也可以用UserService继承UserDetailsService

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    AuthorityMapper authorityMapper;

    /*根据前端登录页面传入的用户名,查询出数据库对应的用户信息和用户权限,
    把用户信息和权限封装成UserDetails对象,交给SpringSecurity进行身份认证*/
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        /*根据用户名查询用户信息*/
        User user = userMapper.selectUserByUserName(s);
        /*根据用户名查询权限信息*/
        List<Authority> authorities = authorityMapper.selectAuthorityByUserName(s);

        /*遍历封装用户权限*/
        List<SimpleGrantedAuthority> authorityList = new ArrayList<>();
		for (int i=0; i<authorities.size(); i++){
            authorityList.add(new SimpleGrantedAuthority(authorities.get(i).getAuthority()));
        }

		// 如果用户不存在
        if(user!=null){
            /*将用户名、密码、用户权限封装成UserDetails对象*/
            UserDetails userDetails = new User(user.getUsername(),encoder.encode(user.getPassword()),authorityList);
            return userDetails;
        }else {
            throw new UsernameNotFoundException("用户不存在");
        }
    }
}

编写UserMapper类:这里仅仅编写了Mapper层逻辑,至于domain与数据库sql就不再赘述了

@Mapper
public interface UserMapper {

 /*根据用户名去查询用户讯息*/
@Select("select * from t_user where username=#{username}")
	public TUser selectUserByUserName(String username);
}
@Mapper
public interface AuthorityMapper {

 /*根据用户名去查询用户权限*/
 @Select(" select a.* from t_user u,t_authority a,user_authority au where u.id=au.uid and a.id=au.aid and u.username=#{username}")
public List<Authority> selectAuthorityByUserName(String username);
}

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

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

相关文章

Android 面试—深入理解Android类加载机制

前言 任何一个java程序都是由一个或者多个class文件组成&#xff0c;在程序运行时&#xff0c;需要将class文件加载到JVM中才可以使用&#xff0c;负责加载这些class文件的就是java的类加载机制。ClassLoader的作用简单的来说就是加载class文件&#xff0c;提供给程序运行时使…

结构体联合体sizeof内存求值 - 对齐数

讲解下struct和union的内存求值和对齐 以题目讲解 结构体联合体sizeof内存求值 - 对齐数不同位数下类型字节大小内存对齐规则struct 内存对齐求值嵌套struct内存对齐求值union的内存大小求值union大小计算准则struct嵌套union内存对齐求值不同位数下类型字节大小 一定要搞清楚…

【机器学习】P18 反向传播(导数、微积分、链式法则、前向传播、后向传播流程、神经网络)

反向传播反向传播反向传播中的数学导数与python链式法则简单神经网络处理流程从而理解反向传播神经网络与前向传播神经网络与反向传播反向传播 反向传播&#xff08;back propagation&#xff09;是一种用于训练神经网络的算法&#xff0c;其作用是计算神经网络中每个参数对损…

【Java虚拟机】JVM核心基础和常见参数实战

1.新版JVM内存组成部分和堆空间分布 JVM内存的5大组成&#xff08;基于JDK8的HotSpot虚拟机&#xff0c;不同虚拟机不同版本会有不一样&#xff09; 名称作用特点程序计数器也叫PC寄存器&#xff0c;用于记录当前线程执行的字节码指令位置&#xff0c;以便线程在恢复执行时能…

常见的DNS攻击与相应的防御措施

DNS查询通常都是基于UDP的&#xff0c;这就导致了在查询过程中验证机制的缺失&#xff0c;黑客很容易利用该漏洞进行分析。DNS服务可能面临如下DNS攻击风险&#xff1a; 黑客伪造客户端源IP地址发送大量的DNS请求报文&#xff0c;造成DNS request flood攻击。 黑客伪造成授权服…

MongoDB实现---存储机制

储存 GridFS机制 GridFS&#xff1a;将大文件分隔成多个小文档存放&#xff0c;这样我们能够有效的保存大文档&#xff0c;而且解决了BSON对象有限制的问题&#xff1b;通过两个集合实现&#xff1a;两个集合分别存储存储实际数据和存储文件的元数据&#xff1a; 元数据文件&…

一篇文章搞定《动手学深度学习》-(李沐)PyTorch版本的所有内容

目录 目录 简介 阅读指南 1. 深度学习简介 2. 预备知识 3. 深度学习基础 4. 深度学习计算 5. 卷积神经网络 6. 循环神经网络 7. 优化算法 8. 计算性能 9. 计算机视觉 10. 自然语言处理 环境 参考&#xff08;大家可以在这里下载代码&#xff09; 原书地址&#…

四结(4.13)多线程学习

今天又进行了一次学长授课&#xff0c;关于MySQL和JDBC本来学了增删查改操作&#xff0c;用IDEA也可以操作数据库&#xff0c;今天讲了一些数据库的规范&#xff08;三大范式&#xff09;、以及er图。了解了一下项目。 项目要分为客户端和服务端&#xff08;C/S&#xff09;来写…

vue面试题2023

1.$route和$router的区别? routes : 数组。 路由匹配规则 router &#xff1a; 对象。 路由对象 $router &#xff1a; 对象。 用于跳转路由 和 传递参数 $route &#xff1a;对象。 用于接收路由跳转参数 1.Vue的生命周期方法有哪些&#xff1f; - beforeCreate 初始化实…

科技云报道:“云减碳”成趋势,如何用“计算”帮助企业碳减排?

科技云报道原创。 将数据中心“丢进”水里、“扔进”山里&#xff0c;使用风能、太阳能等清洁能源为数据中心供电……这些都是通过物理方法为数据中心减碳。 数据中心的重要工作在于计算&#xff0c;计算导致了能源消耗&#xff0c;使其成为耗能大户&#xff0c;而通过云计算…

基于imx8m plus开发板全体系开发教程1:Windows/Linux 开发环境配置(连载中)

前言&#xff1a; i.MX8M Plus 开发板是一款拥有 4 个 Cortex-A53 核心&#xff0c;运行频率 1.8GHz;1 个 Cortex-M7 核心&#xff0c;运行频率 800MHz;此外还集成了一个 2.3 TOPS 的 NPU&#xff0c;大大加速机器学习推理。 全文所使用的开发平台均为与NXP官方合作的FS-IMX8…

Terraform 系列-什么是 IaC?

系列文章 &#x1f449; Terraform 系列文章 前言 聊到 Terraform, 必然绕不开 IaC 这个概念&#xff1f;那么&#xff0c;什么是 IaC? &#x1f914; 基本概念 基础架构即代码 (Infrastructure as Code, IaC) 是指通过代码而不是手动流程/控制台点击来管理和配置基础架构…

互联网+制造业:图扑数字孪生智慧工厂车间生产线

前言 随着信息技术、自动化技术和人工智能等技术的快速发展和应用&#xff0c;智能制造已成为全球制造业发展的主流趋势。智能制造是将智能化、自动化、数字化和网络化等技术手段运用到制造过程中&#xff0c;使生产过程具有高度智能化、自动化和数字化的特点&#xff0c;进而…

Linux安装宝塔,并实现公网远程登录宝塔面板【内网穿透】

文章目录前言1. 安装宝塔2. 安装cpolar内网穿透3. 远程访问宝塔4. 固定http地址5. 配置二级子域名6. 测试访问二级子域名转发自CSDN远程穿透的文章&#xff1a;Linux安装宝塔&#xff0c;并实现公网远程登录宝塔面板【内网穿透】 前言 宝塔面板作为建站运维工具&#xff0c;它…

网络编程2(套接字编程)

套接字编程UDP协议通信&#xff1a;TCP通信&#xff1a;套接字编程&#xff1a;如何编写一个网络通信程序 1.网络通信的数据中都会包含一个完整的五元组&#xff1a; sip&#xff0c;sport&#xff0c;dip&#xff0c;dport&#xff0c;protocol&#xff08;源IP&#xff0c;源…

计算机组成原理——第三章存储系统(上)

提示&#xff1a;吾与春风皆过客&#xff0c;君携秋水揽星河 文章目录前言3.1 存储系统基本概念3.2.1 主存储器的基本组成3.2.2 SRAM DRAM\3.2.3 只读存储器ROM3.3.1 主存储器与CPU的连接3.3.2 双端口RAM和多模块存储器前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c…

带你理解运算放大器

复习一下电子设计基本元器件&#xff0c;运算放大器 ...... 矜辰所致目录前言一、运放基本说明1.1 基本认识1.2 运放中的电流1.3 运放工作特性二、负反馈2.1 什么是负反馈&#xff1f;2.2 为什么要引入负反馈&#xff1f;负反馈电路分析2.3 正反馈三、提一下虚短与虚断结语前…

MAX14808 八通道3级电平 数字脉冲发生器

MAX14808八通道3级电平 高压(HV) 脉冲发生器&#xff0c;利用低压控制逻辑输入产生高频、高压双极性脉冲(高达105V) &#xff0c;用于驱动超声系统的压电传感器&#xff0c;MAX14808有八个集成的发送/接收(T/R)开关。 应用 超声医疗成像工业探伤检测压电驱动器测试设备 芯片…

RocketMQ 是是如何管理消费进度的?又是如何保证消息成功消费的?

RocketMQ 消费者保障 作者: 博学谷狂野架构师GitHub&#xff1a;GitHub 地址 &#xff08;有我精心准备的 130 本电子书 PDF&#xff09;只分享干货、不吹水&#xff0c;让我们一起加油&#xff01;&#x1f604; 消息确认机制 consumer 的每个实例是靠队列分配来决定如何消费消…

五、MyBatis各种查询功能

MyBatis的各种查询功能 如果查询出的数据只有一条&#xff0c;可以通过 实体类对象接收List集合接收Map集合接收 如果查询出的数据有多条&#xff0c;一定不能用实体对象接收&#xff0c;会抛TooManyResultsException&#xff0c;可以通过 实体类类型的List集合接收Map类型的L…