SpringSecurity基础入门详解

news2024/9/20 18:40:22

【1】SpringSecurity是什么

Spring 是非常流行和成功的 Java 应用开发框架,Spring Security正是Spring家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。

正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控制),一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两点也是Spring Security重要核心功能。

  • (1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。通俗点说就是系统认为用户是否能登录
  • (2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。通俗点讲就是系统判断用户是否有权限去做某些事情。

官网地址:https://spring.io/projects/spring-security

SpringSecurity特点:

  • 和Spring无缝整合。
  • 全面的权限控制。
  • 专门为Web开发而设计。
    • 旧版本不能脱离Web环境使用。
    • 新版本对整个框架进行了分层抽取,分成了核心模块和Web模块。单独引入核心模块就可以脱离Web环境。
  • 重量级。

Apache旗下的轻量级权限控制框架Shiro

  • 轻量级。Shiro主张的理念是把复杂的事情变简单。针对对性能有更高要求的互联网应用有更好表现。
  • 通用性。
  • 好处:不局限于Web环境,可以脱离Web环境使用。
  • 缺陷:在Web环境下一些特定的需求需要手动编写代码定制。

Spring Security 是 Spring 家族中的一个安全管理框架,实际上,在 Spring Boot 出现之前,Spring Security 就已经发展了多年了,但是使用的并不多,安全管理这个领域,一直是 Shiro 的天下。

相对于 Shiro,在 SSM 中整合 Spring Security 都是比较麻烦的操作,所以,Spring Security 虽然功能比 Shiro 强大,但是使用反而没有 Shiro 多(Shiro 虽然功能没有 Spring Security 多,但是对于大部分项目而言,Shiro 也够用了)。 自从有了 Spring Boot 之后,Spring Boot 对于 Spring Security 提供了自动化配置方案,可以使用更少的配置来使用 Spring Security。

因此,一般来说,常见的安全管理技术栈的组合是这样的:

  • SSM + Shiro
  • Spring Boot/Spring Cloud + Spring Security

【2】权限管理中的相关概念

① 主体

英文单词:principal

使用系统的用户或设备或从其他系统远程登录的用户等等。简单说就是谁使用系统谁就是主体。

② 认证

英文单词:authentication

权限管理系统确认一个主体的身份,允许主体进入系统。简单说就是“主体”证明自己是谁。笼统的认为就是以前所做的登录操作。

③ 授权

英文单词:authorization

将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。所以简单来说,授权就是给用户分配权限。

【3】入门案例

创建一个基本工程,pom文件引入依赖如下:

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

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

编写controller,启动项目测试请求:

@GetMapping("hello")
public String hello() {
    return "hello security";
}

浏览器访问请求:http://localhost:8111/test/hello,此时会重定向到 http://localhost:8111/login 登录页面。

在这里插入图片描述

idea控制台,此时有打印的用户密码(用户名默认是user,密码每次自动生成):

在这里插入图片描述
登录之后,再次访问请求会放行。如上所示就是spring-security的一个基础表现,那么其实现原理以及如何在我们项目中使用呢?我们逐步学习。这里我们可以提前说一下,其本质就是一个过滤器链,有没有联想到哪种设计模式呢?

【4】UserDetailsService接口

当什么也没有配置的时候,账号和密码是由Spring Security定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。 所以我们要通过自定义逻辑控制认证逻辑。

如果需要自定义逻辑时,只需要实现UserDetailsService接口即可。接口定义如下:

package org.springframework.security.core.userdetails;
public interface UserDetailsService {

	//根据用户名检索得到用户信息
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

UserDetails 接口如下所示:

// 表示获取登录用户所有权限 
Collection<? extends GrantedAuthority> getAuthorities(); 
// 表示获取密码 
String getPassword(); 
// 表示获取用户名 
String getUsername(); 
// 表示判断账户是否过期 
boolean isAccountNonExpired(); 
// 表示判断账户是否被锁定 
boolean isAccountNonLocked(); 
// 表示凭证{密码}是否过期 
boolean isCredentialsNonExpired(); 
// 表示当前用户是否可用 
boolean isEnabled();

其实现类如下所示,这里的org.springframework.security.core.userdetails.User就是我们要研究的核心。
在这里插入图片描述
在这里插入图片描述

【5】PasswordEncoder接口

上面我们看到user对象中密码是需要加密的,如何处理呢?就是使用PasswordEncoder接口。

加密接口,首选实现是BCryptPasswordEncoder。

public interface PasswordEncoder {

	 // 按照某种规则进行加密
	String encode(CharSequence rawPassword);
	
//表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配,前者表示原始密码,后者是加密后的密码
	boolean matches(CharSequence rawPassword, String encodedPassword);

//表示如果加密的密码能够再次进行加密达到更安全的结果则返回true,否则返回false。
//默认返回false。
	default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}
}

BCryptPasswordEncoder是Spring Security官方推荐的密码解析器,平时多使用这个解析器。

BCryptPasswordEncoder是对bcrypt强散列方法的具体实现。是基于Hash算法实现的单向加密。可以通过strength控制加密强度,默认10。

【6】设置登录的用户名和密码

通常有三种方式:

  • 通过配置文件
  • 编写配置类
  • 自定义实现类

① application.properties

也就是在配置文件配置用户名密码:

spring.security.user.name=jane
spring.security.user.password=123456

请求访问-跳转登录,输入配置的用户密码即可。这种场景通常是需要指定某个账号密码访问服务,比如eureka等访问。

在这里插入图片描述

② 编写配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123456");
        auth.inMemoryAuthentication().withUser("jane").password(password)
        .roles("admin");//假设角色是admin
    }

	//注入加密器实例
    @Bean
    PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
}

如此就直接在配置类指定了用户名和密码,测试结果同上。

③ 自定义实现类

  • 修改配置类,设置使用哪个userDetailService实现类
  • 编写实现类,返回User对象,User对象有用户名密码和操作权限

修改配置类如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    }

    @Bean
    PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
}

自定义实现类如下:

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      
        List<GrantedAuthority> auths =
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
        //从查询数据库返回users对象,得到用户名和密码,返回
        return new User("jane",new BCryptPasswordEncoder().encode("123456"),auths);
    }
}

这里用户名和密码仍然是指定的,但是我们是不是可以升级为从数据库查询?

【7】集成MP查询数据库完成认证

也就是对【6】中第③进行升级,从数据库查询信息来完成认证。

① 引入依赖

<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

配置数据库信息:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

② 编写代码

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("sys_user")
public class SysUser {
    private Integer id;
    private String username;
    private String password;
}

对应数据库表信息:

CREATE TABLE `sys_user` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

UserMapper

@Repository
public interface UserMapper extends BaseMapper<SysUser> {
}

修改自定义实现类:

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //调用usersMapper方法,根据用户名查询数据库
        QueryWrapper<SysUser> wrapper = new QueryWrapper();
        // where username=?
        wrapper.eq("username",username);
        SysUser users = userMapper.selectOne(wrapper);
        //判断
        if(users == null) {//数据库没有用户名,认证失败
            throw  new UsernameNotFoundException("用户名不存在!");
        }
        List<GrantedAuthority> auths =
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
        //从查询数据库返回users对象,得到用户名和密码,返回
//return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);
    //这种格式,数据库存储密码为明文
       
        return new User(users.getUsername(),users.getPassword(),auths); 
        //这种格式,数据库存储密码为密文       
    }
}

主启动类添加扫描注解

@MapperScan("com.jane.mapper")
@SpringBootApplication
public class Securitydemo1Application {
    public static void main(String[] args) {
        SpringApplication.run(Securitydemo1Application.class, args);
    }
}

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

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

相关文章

使用英特尔 oneAPI AI 工具分析包实现AI应用程序的调试与改进

目录 1.什么是英特尔 oneAPI AI&#xff1f; 关于英特尔 oneAPI AI 工具分析包 2.使用英特尔 oneAPI AI 工具分析包实现AI数据分析 准备工作 数据准备 编写AI应用程序 性能分析 并行性优化 内存和线程错误分析 优化AI算法 性能验证与调试 性能优化迭代 3.总结 1.什…

「2024」预备研究生mem-概率基础加法公式乘法公式古典概型基础

一、概率基础 二、加法公式 三、乘法公式&古典概型基础 均不是1点 除了不是1的概率 不全是1点&#xff1a;也有可能是1点&#xff0c; 理解为 对是1点取非 相互独立 相乘 古典概型&#xff1a; 从A出发&#xff0c;先到B&#xff0c; 先到D&#xff0c;先到C&#xff08;…

记录字符串压缩

参考代码 class Solution { public:string num2str(int val){string ans;while(val/10){ans.push_back((char)(0val%10));val/10;}ans.push_back((char)(0val%10));return ans;}string compressString(string S) {string ssS;S.push_back(\n);int left0,right1;int n S.size(…

数字孪生场景渲染能力中的WebGL技术路线

使用三维建模技术构建出的虚拟现实场景后&#xff0c;需要通过渲染引擎实现场景的高精度、高保真和实时渲染。同时&#xff0c;需要将现实场景中的数据信息融合到虚拟场景中&#xff0c;实现对现实情况的监测和控制。 目前大多数数字孪生城市项目在三维渲染引擎的技术选型上通…

高性能哈希算法MurmurHash

参考链接&#xff1a; https://blog.51cto.com/u_15127622/3264772 md5算法_十分钟掌握高性能哈希算法MurmurHash_weixin_39616339的博客-CSDN博客 Murmur哈希算法 一种非加密型哈希算法&#xff0c;适用于一般的哈希检索操作&#xff0c;由Austin Appleby创建于2008年。 …

Nat.Commun.:展示了首个硅量子光源!

光子盒研究院 量子技术有望通过启用全新的通信、传感和计算方法来彻底改变社会。例如&#xff0c;量子密码学如果能够实现&#xff0c;将为抵御黑客提供无与伦比的数据安全水平&#xff1a;这是因为量子信息可以在光子&#xff08;单个光粒子&#xff09;中进行编码、无法被复制…

以数为帆,乘风破浪!数据治理与应用沙龙在广州成功举办

DCMM作为国家第一个数据管理领域标准&#xff0c;是企业落实数据驱动战略、实现数字化转型的重要抓手。当下每个企业都必须有自己的数字化转型战略&#xff0c;而数据治理和数字化转型是同生共伴的&#xff0c;DCMM可以为企业进行数据治理提供全面的模型指导和方法体系。 6月2…

精选Golang高频面试题和答案汇总

大家好&#xff0c;我是阳哥。 之前写的《 GO必知必会面试题汇总》&#xff0c;已经阅读破万&#xff0c;收藏230。 也欢迎大家收藏、转发本文。 这篇文章给大家整理了17道Go语言高频面试题和答案详解&#xff0c;每道题都给出了代码示例&#xff0c;方便大家更好的理解。 1…

输入数据时全连接层计算量是多少

假设是这样的 那么计算公式是这样的 [ a 1 a 2 a 3 ] [ W 11 W 12 W 21 W 22 W 31 W 32 ] [ x 1 x 2 ] [ b 1 b 2 b 3 ] \left[\begin{array}{l} a_1 \\ a_2 \\ a_3 \end{array}\right]\left[\begin{array}{ll} W_{11} & W_{12} \\ W_{21} & W_{22} \\ W_{31} &…

关于uCOSiii使用__get_MSP()返回主堆栈指针的当前值出现的问题

关于uCOSiii使用__get_MSP()返回主堆栈指针的当前值出现的问题 我的uCOSiii的版本是: V3.03.01 void STACK_Init(void) { Used_STACK_SIZE0; STACK_BOTTOM*(vu32 *)STM32_FLASH_BASE_ADDRESS1;//取APP的SP初值 STACK_TOP1STACK_BOTTOM; } //函数功能:在中断函数…

cookies、localStorage 、sessionStorage 的区别

共同点&#xff1a;三者都是浏览器的本地存储。 区别&#xff1a; 存储位置&#xff1a;cookie是由服务器端写入的&#xff0c;而SessionStorage、LocalStorage都是由前端写入的&#xff1b; 存储大小&#xff1a;cookie的存储空间比较小&#xff0c;大概4KB,而SessionStorag…

webpack编译微信小程序

微信小程序开发目前主要还是依赖小程序原生开发者工具&#xff0c;但开发者工具目前还不支持常用的less、sass样式编译&#xff0c;以及环境变量配置等功能。使用webpack就可以弥补这些问题。 思路 webpack启动后&#xff0c;通过webpack-shell-plugin-next包执行启动后的一些…

沉浸式翻译

chrome沉浸式翻译插件 网页双语翻译&#xff0c;完全免费使用&#xff0c;支持Deepl/Google/Bing/腾讯/有道等。 一款免费、用户友好、简洁、革命性、广受好评的人工智能双语网络翻译扩展程序&#xff0c;可帮助您有效地弥合信息差距&#xff0c;也可在移动设备上使用&#xff…

【ArcGIS Pro二次开发】(44):属性结构描述表【Excel】转空库(批量)

随着县级国土空间总体规划数据库规范的下发&#xff0c;建立标准空库是一项马上就要着手的工作。国空的数据库体量很大&#xff0c;单是要素类就有100多个&#xff0c;不是以前村规数据库能比的&#xff0c;手动建库是不可能的&#xff0c;工具自动建库就是一个很合理的选择。 …

短视频seo矩阵系统源码开发思路

短视频SEO矩阵系统源码开发&#xff0c;需要遵循一下步骤&#xff1a; 1. 确定需求和功能&#xff1a;明确系统的主要目标和需要实现的功能&#xff0c;包括关键词研究、短视频制作、外链建设、数据分析、账号设置优化等方面。 2. 设计系统架构&#xff1a;根据需求和功能确定…

2023第二届中国汽车碳中和国际峰会 嘉宾更新

The 2nd China Automotive Carbon Neutral Summit 2023 2023第二届中国汽车碳中和国际峰会 嘉宾更新 Event Background会议背景 As the world increasingly recognizes the devastating impact of climate change, governments, organizations, and individuals are taking a…

如何安装微信小程序开发工具

1、点击进入微信开发者工具&#xff08;稳定版 Stable Build&#xff09;下载地址&#xff0c;选择Win64的版本下载。 2、运行exe程序&#xff0c;可能会出现微软商城安全提醒&#xff0c;不用理睬&#xff0c;直接点运行。 3、点击“下一步”。 4、点击“我接受”。 5、选择安…

vant-weapp源码解析(一)

想每天做点新东西&#xff0c;因此有此记录 这是进入的第一个页面&#xff0c;里面有引入list&#xff0c;page。 config.js:这是路径配置文件 page.js&#xff0c;外层配置文件 options,就算引入这个page.js页面所传递的数据 点击进入导航&#xff0c;看第一个按钮组件 button…

秋招二本4年Java经验,五面字节(定薪45K)

前段时间刚面试上岸&#xff0c;先后面试了各大小公司&#xff0c;拿了一些 offer&#xff0c;有阿里&#xff0c;滴滴&#xff0c;快手&#xff0c;达达&#xff0c;得物等公司。面试的公司大部分都能过&#xff0c;所以这里给大家分享下自己的经验&#xff0c;也给自己做个归…

学习Vue3——生命周期

简单来说就是一个组件从创建到销毁的过程称为生命周期 Vue 2 生命周期钩子函数Vue 3 生命周期钩子函数含义beforeCreatesetup在实例初始化之后、数据观测 (data observer) 和 event/watcher 事件配置之前被调用createdsetup在实例创建完成后被立即调用。在这一步&#xff0c;实…