一、简介
本文主要是介绍权限管理中认证与授权的概念、权限管理框架有哪些、简单介绍Spring Security
,不涉及原理详细讲解,通过一个入门案例来引入SpringBoot
中怎么使用Spring Security
。
本文和接下来的几篇文章不涉及原理详细讲解,都是在讲解怎么去使用它,然后会有一篇讲解认证与授权的源码文章,最后会有一个完整的用户认证与授权的代码编写(SpringBoot + Spring Security + MyBatis-Plus +JWT+Redis)
。
二、前置知识
基本上涉及用户参与的系统都需要进行权限管理,我们知道权限管理包括用户认证
和授权
两部分,简称认证授权。
- 什么是认证?
用户认证就是判断一个用户的身份是否合法的过程,常见的认证方式有:用户名密码登录、二维码登录、手机短信登录、指纹认证、人脸识别等。
- 什么是授权?
授权是指用户通过认证后,根据用户的权限来控制用户访问资源的过程。如果拥有资源的访问权限则正常访问,否则就拒绝访问。
- 什么是会话?
用户通过认证后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制,常见的有基于session方式、基于token方式等。可以参考我这篇文章 Session 认证和 Token 认证
三、安全框架实现
在Java
企业级开发中,安全框架比较少,比较常见的是:
- Shiro: 本身是一个老牌的安全管理框架,轻量、简单、易于集成,提供认证、授权、会话管理、密码管理、缓存管理等功能。
- Spring Security: 功能比 Shiro 强大,更复杂,权限控制细粒度更高,对 OAuth2 支持更好,与 Spring 框架无缝集合,方便与 SpringBoot 集成。
- 开发者自定义:有很多公司选择自定义权限,即自己开发权限管理。需要大量的人力物力。
四、SpringSecurity
介绍
Spring Security
是一个提供身份验证、授权和防止常见攻击的框架。用户认证(Authentication)
和用户授权(Authorization)
是 Spring Security
重要核心功能。
官方文档:
中文:
6版本:spring-security6.X中文官网
5版本:spring-security5.X中文网址
英文:5版本:spring-security5.X英文网址6版本:spring-security6.X英文网址
注意:
SpringBoot 2.X
版本支持的是SpringSecurity 5.X
。
SpringBoot3.x
版本支持的是SpringSecurity 6.x
SpringSecurity5.X 与 SpringSecurity6.X 功能一样,用法几乎一致 ,区别是授权模块,SpringSecurity6.X
底层作了很大改动,部分类被放弃。
本教程使用SpringBoot2.X 版本,对应的是SpringSecurity 5.X。
五、入门案例
5.1、创建SpringBoot
项目
先要搭建一个SpringBoot
工程。
步骤1:设置依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.duan</groupId>
<artifactId>springsecurity</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>
**步骤2:**创建application.yml
和application-dev.yml
文件
application.yml
server:
port: 8183
servlet:
context-path: /security # 应用名
spring:
profiles:
active: dev
application-dev.yml
server:
port: 8183
servlet:
context-path: /security # 应用名
**步骤3:**创建启动类
package com.duan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author db
* @version 1.0
* @description SpringSecurityApplication
* @since 2024/7/11
*/
@SpringBootApplication
public class SpringSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityApplication.class);
}
}
**步骤4:**创建controller
package com.duan.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author db
* @version 1.0
* @description TestController
* @since 2024/7/11
*/
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/testMethod")
public String testMethod(){
return "测试方法";
}
}
**步骤6:**启动并访问
在浏览器访问资源: http://localhost:8183/security/test/testMethod
, 会发现访问资源被拦截了,spring Security
默认提供认证页面,不需要额外开发。
运行结果说明 Spring Security
默认拦截了所有请求,但登录退出不拦截。使用默认账号是 user
登录系统,密码是随机生成的 UUID
字符串,在控制台上可以找到。
输入用户名密码可以看到可以访问该方法。
步骤7:退出登录
单击Log Out
按钮,成功退出。
引入spring-boot-starter-security
依赖后,项目中除登录退出外所有资源都会被保护起来。
认证(登录)用户可以访问所有资源,不经过认证用户任何资源也访问不了。
所有资源均已保护,但用户只有一个,密码是随机的,只能在开发环境中使用,有没有其他方式进行用户名密码配置?
5.2、使用配置文件配置用户名和密码
修改上面项目中的application-dev.yml
,如下:
spring:
profiles:
active: dev
security:
user:
name: admin
password: 123qaz
启动运行使用浏览器测试发现使用配置文件中的用户名和密码可以正常访问。配置文件中配置用户后,默认的 user
用户就没有了。示例说明:可以通过配置文件配置用户和密码,解决了使用随机生成密码的问题。
5.3、通过配置类配置用户名和密码
首先在上面项目中注释掉yml
文件中关于Spring Security
用户名和密码的配置,然后新建一个配置类SecurityConfig
package com.duan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* @author db
* @version 1.0
* @description SecurityConfig
* @since 2024/7/15
*/
@Configuration
public class SecurityConfig {
//配置用户信息服务
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("cxykk").password(passwordEncoder().encode("123qwe")).authorities("p1").build());
manager.createUser(User.withUsername("cxydb").password(passwordEncoder().encode("123qaz")).authorities("p2").build());
return manager;
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
启动程序测试登录页面输入用户名(cxykk)和密码(123qwe)
,然后单击登录后,控制台报错,如下:
报错的原因如下:
是因为 spring Sercurity
强制要使用密码加密,当然也可以不加密,但是官方要求是不管你是否加密,都必须配置一个密码编码器。
在 SecurityConfig
中添加密码编码器 Bean
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
重启程序再次使用 cxykk/123qwe
登录测试,可以登录正常访问了。
5.4、密码处理
密码加密一般使用散列函数,又称散列算法,哈希函数,这些函数都是单向函数(从明文到密文,反之不行)常用的散列算法有 MD5
和 SHA
。
Spring Security
提供多种密码加密方案,基本上都实现了 PasswordEncoder
接口,官方推荐使用 BCryptPasswordEncoder
新建测试类 SecurityTest
如下:
package com.duan;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author db
* @version 1.0
* @description SecurityTest
* @since 2024/7/17
*/
public class SecurityTest {
@Test
public void test1(){
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
// 加密 从明文到密文
String encode = bCryptPasswordEncoder.encode("123456");
System.out.println(encode);
String encode2 = bCryptPasswordEncoder.encode("123456");
System.out.println(encode2);
String encode3 = bCryptPasswordEncoder.encode("123456");
System.out.println(encode3);
// 匹配方法
boolean result1 = bCryptPasswordEncoder.matches("123456", encode);
System.out.println("result1 "+result1);
boolean result2 = bCryptPasswordEncoder.matches("123456", encode2);
System.out.println("result1 "+result2);
boolean result3 = bCryptPasswordEncoder.matches("123456", encode3);
System.out.println("result1 "+result3);
}
}
执行程序,得到结果发现
相同的字符串加密之后的结果都不一样,但是比较的时候是一样的,因为加了盐(salt)
六、总结
这是 Spring Security
成长之路第一篇文章,主要学习 Spring Security
框架的基础,从一个入门案例来初探Spring Security
简单原理以及执行流程,通过配置文件和配置类来加深理解用户认证,其实在项目中肯定不是用配置文件或者配置文件去进行用户认证,主要是想通过不同的方式去理解它的原理与业务逻辑。项目中用的最多还是查询数据库进行数据认证,这个后面会详细讲解。
其实我们没有动手之前,从其他资料上了解到它多么复杂、那么多配,怎么去学习,根本无从下手,可是到了真正去学习时,我们可以查资料、看视频去学习,主要的还是自己真正动手去做。
改变你能改变的,接受你不能改变的,关注公众号:程序员康康,一起成长,共同进步。