# springSecurity
**Repository Path**: misszyg/spring-security
## Basic Information
- **Project Name**: springSecurity
- **Description**: 学习springSecurity
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 3
- **Created**: 2023-03-10
- **Last Updated**: 2024-07-02
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 2022.11.28完结!!!!
# SpringSecurity学习记录(B站三更草堂)
## 简介
**Spring Security** 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架 **Shiro**,它提供了更丰富的功能,社区资源也比 Shiro 丰富。
一般来说中大型的项目都是使用 **SpringSecurity** 来做安全框架。小项目有 Shiro 的比较多,因为相比与 SpringSecurity,Shiro 的上手更加的简单。
一般 Web 应用的需要进行**认证**和**授权**。
**认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户**
**授权:经过认证后判断当前用户是否有权限进行某个操作**
而认证和授权也是 SpringSecurity 作为安全框架的核心功能。
## 1. 快速入门
### 1.1 准备工作
我们先要搭建一个简单的 SpringBoot 工程
① 设置父工程 添加依赖
```java
org.springframework.boot
spring-boot-starter-parent
2.5.0
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
true
```
② 创建启动类
```java
@SpringBootApplication
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
```
③ 创建 Controller
```java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
```
### 1.2 引入 SpringSecurity
在 SpringBoot 项目中使用 SpringSecurity 我们只需要引入依赖即可实现入门案例。
```java
org.springframework.boot
spring-boot-starter-security
```
引入依赖后我们在尝试去访问之前的接口就会自动跳转到一个 SpringSecurity 的默认登陆页面,默认用户名是 user, 密码会输出在控制台。
必须登陆之后才能对接口进行访问。
## 2. 认证
### 2.1 登陆校验流程

### 2.2 原理初探
想要知道如何实现自己的登陆流程就必须要先知道入门案例中 SpringSecurity 的流程。
2.2.1 SpringSecurity 完整流程
SpringSecurity 的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。这里我们可以看看入门案例中的过滤器。

图中只展示了核心过滤器,其它的非核心过滤器并没有在图中展示。
**UsernamePasswordAuthenticationFilter**: 负责处理我们在登陆页面填写了用户名密码后的登陆请求。入门案例的认证工作主要有它负责。
**ExceptionTranslationFilter:** 处理过滤器链中抛出的任何 AccessDeniedException 和 AuthenticationException 。
**FilterSecurityInterceptor:** 负责权限校验的过滤器。
我们可以通过 Debug 查看当前系统中 SpringSecurity 过滤器链中有哪些过滤器及它们的顺序。

2.2.2 认证流程详解

概念速查:
Authentication 接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。
AuthenticationManager 接口:定义了认证 Authentication 的方法
UserDetailsService 接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。
UserDetails 接口:提供核心用户信息。通过 UserDetailsService 根据用户名获取处理的用户信息要封装成 UserDetails 对象返回。然后将这些信息封装到 Authentication 对象中。
### 2.3 解决问题
2.3.1 思路分析
登录
①自定义登录接口
调用 ProviderManager 的方法进行认证 如果认证通过生成 jwt
把用户信息存入 redis 中
②自定义 UserDetailsService
在这个实现类中去查询数据库
校验:
①定义 Jwt 认证过滤器
获取 token
解析 token 获取其中的 userid
从 redis 中获取用户信息
存入 SecurityContextHolder
2.3.2 准备工作
①添加依赖
```java
org.springframework.boot
spring-boot-starter-data-redis
com.alibaba
fastjson
1.2.33
io.jsonwebtoken
jjwt
0.9.0
```
② 添加 Redis 相关配置
```java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.util.Assert;
import java.nio.charset.Charset;
/**
* Redis使用FastJson序列化
*
* @author sg
*/
public class FastJsonRedisSerializer implements RedisSerializer
{
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class clazz;
static
{
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
}
public FastJsonRedisSerializer(Class clazz)
{
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException
{
if (t == null)
{
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException
{
if (bytes == null || bytes.length <= 0)
{
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz);
}
protected JavaType getJavaType(Class> clazz)
{
return TypeFactory.defaultInstance().constructType(clazz);
}
}
```
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public RedisTemplate