SpringSecurity框架【认证】

目录

一. 快速入门

二. 认证

2.1 登陆校验流程

2.2 原理初探

2.3 解决问题

2.3.1 思路分析

2.3.2 准备工作

2.3.3 实现

2.3.3.1 数据库校验用户

2.3.3.2 密码加密存储

2.3.3.3 登录接口

2.3.3.4 认证过滤器

2.3.3.5 退出登录


Spring Security是Spring家族中的一个安全管理框架,相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。

一般来说大型项目用Spring Security比较多,小项目用Shiro比较多,因为相比于Spring Security,Shiro上手比较简单。

一般Web应用需要进行认证授权

  • 认证:验证当前访问系统的是不是本系统用户,并且要确认具体是哪个用户
  • 授权:经过认证后判断当前用户是否有权限进行某个操作

而认证和授权正是Spring Security作为安全框架的核心功能!

一. 快速入门

我们先简单构建出一个SpringBoot项目。

这个时候我们访问我们写的一个简单的hello接口,验证是否构建成功。

接着引入SpringSecurity。

这个时候我们再看看访问接口的效果。

引入了SpringSecurity之后,访问接口会自动跳转到一个登录页面,默认的用户名是user,密码会输出到控制台,必须登录后才能对接口进行访问。

二. 认证

2.1 登陆校验流程

首先我们要先了解登录校验流程,首先前端携带用户名和密码访问登录接口,服务器拿到这个用户名和密码之后去和数据库中的进行比较,如果正确使用用户名/用户ID,生成一个jwt,接着把jwt响应给前端,之后登录后访问其他的请求都会在请求头中携带token,服务器每次获取请求头中的token进行解析、获取UserID,根据用户名id获取用户相关信息,查看器权限,如果有权限则响应给前端。

2.2 原理初探

SpringSecurity的原理其实就是一个过滤器链,内部提供了各种功能的过滤器,这里我们先看看上方快速入门中涉及的过滤器。

  • UsernamePasswordAuthenticationFilter负责处理在登录页面填写的用户名密码后的登录请求
  • ExceptionTranslationFilter处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException
  • FilterSecurityInterceptor负责权限校验的过滤器

我们也可以通过Debug查看当前系统中SpringSecurity过滤器链中有哪些过滤器以及顺序。

接下来我们来看看认证流程图的解析。

这里我们只需要能看懂其过程即可,简单来说就是:

用户提交了用户名和密码,UsernamePasswordAuthenticationFilter将其封装未Authentication对象,并且调用authenticate方法进行认证,接着在调用DaoAuthenticationProvider的authenticate方法进行认证,再调用loadUserByUserName方法查询用户,这里的查询是在内存中进行查找,然后将对应的用户信息封装未UserDetails对象,通过PasswordEncoder对比UserDetails中的密码和Authentication的密码是否正确,如果正确就把UserDetails中的权限信息设置到Authentication对象中,接着返回Authentication对象,最后使用SecurityContextHolder.getContext().setAuthentication方法存储该对象,其他过滤器会通过SecurityContextHoder来获取当前用户信息。(这一段不用记忆能听懂即可)

那么我们知道了其过程,才能对其进行修改,首先这里的从内存中查找,我们肯定是要该为从数据库中查找(这里需要我们自定义一个UserDetailsService的实现类),并且也不会使用默认的用户名密码,登录界面也一定是自己编写的,不需要用他提供的默认登录页面。

基于我们分析的情况,可以得到这样的一张图。

这个时候就返回了一个jwt给前端,而这时前端进行的其他请求都会携带token,那么我们第一步就需要先校验是否携带token,并且解析token,获取对应的userid,并且将其封装为Anthentication对象存入SecurityContextHolder(为了其他过滤器可以拿到)。

那么这里还有一个问题,从jwt认证过滤器中取到了userid后如何获取完整的用户信息?

这里我们使用redis,当服务器认证通过使用用户id生成jwt给前端的时候,以用户id作为key,用户的信息作为value存入redis,之后就可以通过userid从redis中获取到完整的用户信息了。

2.3 解决问题

2.3.1 思路分析

从上述的原理初探中,我们也大概分析出了我们要是自己实现前后端分离的认证流程,需要做的事情。

登录:

        a.自定义登录接口

                调用ProviderManager的方法进行认证,如果认证通过生成jwt

                把用户信息存入redis中

        b.自定义UserDetailsService

                在这个实现类中去查询数据库

校验:

        a.自定义jwt认证过滤器

                获取token

                解析token获取其中userid

                从redis中获取完整用户信息

                存入SecurityContextHolder

2.3.2 准备工作

首先需要添加对应的依赖

        <!--   SpringSecurity启动器     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!--   redis依赖     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--   fastjson依赖     -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.33</version>
        </dependency>
        <!--   jwt依赖     -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

接着我们需要用到Redis需要加入Redis相关的配置

首先是FastJson的序列化器

package org.example.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.Charset;

/**
 * Redis使用fastjson序列化
 * @param <T>
 */
public class FastJsonRedisSerializer<T> implements RedisSerialize
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子健变于晏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值