SpringSecurity框架(入门)

简介:

Spring Security 是一个用于构建安全的 Java 应用程序的框架,尤其适用于基于Spring的应用程序。它提供了全面的安全控制,从认证(Authentication)到授权(Authorization),以及一系列的中间件功能,如CSRF防护、会话管理等。以下是Spring Security的核心概念和使用方式的详细说明:

What: Spring Security 是什么?

Spring Security 是一套用于保护Web应用程序免受未经授权访问的框架。它提供了以下核心功能:

  • 认证:验证用户身份,例如通过用户名和密码登录。

  • 授权:控制对资源的访问,例如,只有管理员才能访问某些页面。

  • 会话管理:确保会话安全,防止会话劫持和固定会话攻击。

  • CSRF防护:防止跨站请求伪造(Cross-Site Request Forgery)。

  • 过滤器链 :通过一系列的过滤器来处理HTTP请求,执行安全相关的操作。(我们主要就是写自定义的过滤器)

Why: 为什么使用Spring Security?

  • 声明式安全:通过注解或配置文件轻松声明谁可以访问什么资源,无需手动编写安全检查代码。

  • 高度可定制:可以根据需求调整认证和授权逻辑,支持多种认证和授权机制。

  • 与Spring的集成:无缝集成Spring框架,与Spring Boot、Spring MVC等组件配合良好。

  • 安全功能丰富:提供多种安全特性,覆盖了Web应用安全的多个方面。

How: 如何使用Spring Security?

使用Spring Security通常包括以下步骤:

  • 依赖配置:在项目中引入Spring Security的依赖,如果是Spring Boot项目,可以通过添加相应的starter依赖。

  • 配置安全:创建一个WebSecurityConfigurerAdapter的子类,重写其配置方法来定义安全规则,例如哪些URL需要保护,使用哪种认证方式等。

SpringSecurity认证管理流程

下图是一个简单的Security认证管理流程

快速入门实践

接下来,我们创建一个小的Module感受下SpringSecurity在登录情景下的使用

创建Module

  1. 在当前最外层根目录下,右键,选择 "New"-->"Module"--"Spring Initializer"-->选择"设置"->将初始化服务器地址设置为https://start.aliyun.com国内阿里云
  1. 按照下图所示的内容创建 "securityDemo"
  1. 添加六个依赖

删除原有的demos目录及文件

如图所示修改application.properties

复制代码
   # 应用服务 WEB 访问端口
   server.port=8080

   # 数据库连接信息
   spring.datasource.url=jdbc:mysql://localhost:3306/ivos?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
   spring.datasource.username=root
   spring.datasource.password=root

启动项目,控制台会出现如下图所示的一个密码

复制这个密码,马上要用

访问登录页面

SpringSecurity自己提供了一个登录页,我们可以直接通过 http://localhost:8080/login 访问

  • 默认用户名 user

  • 密码为之前控制台输出的password 1854cb7d-e2ef-4d84-a4f7-df2e18855a24

注意:这个密码每个人不一样,而且这个登录页打开比较慢,需要等一下

认证流程拆分

结合上面的这个登录认证流程,我们来继续补充完善完整的流程,Spring Security 的流程控制涉及了一系列的过滤器,这些过滤器构成了大家俗称的"安全过滤器链"。完整流程是这样的:

  1. 用户尝试访问受Spring Security保护下的URL地址

  2. 访问此URL需要检验有没有认证,Spring Security会检查该请求是否允许放行

  3. 如果 不允许放行

    1. 我们指定的过滤器会返回拒绝访问的状态码,一般为401未授权(SC_UNAUTHORIZED)与403拒绝访问(SC_FORBIDDEN)

    2. 如果在没有登录的情况下,所有的前端请求应该都需要接收到后端返回的未授权状态

  4. 如果 允许放行

    1. 会根据请求调用对应的接口加载资源

      (比如生成接口文档无需验证都可放行http://localhost:8080/doc.html)

    2. 登录请求也不需要验证即可放行,我们需要在表单中拿到用户的身份信息进行进一步的身份认证

      1. Authentication Manager认证管理器会进行用户信息认证

      2. Authentication Provider 会调用UserDetailsService,将用户名与数据库中的用户信息进行匹配,同时验证密码

      3. 如果验证成功,创建一个Authentication认证对象,包含用户及权限信息

    3. 验证成功后,Spring Security会调用配置的AuthenticationSuccessHandler,将用户信息返回给前端

      我们存在localStorage中的userVO就是通过上面的AuthenticationSuccessHandler返回给前端的

进阶练习,在你的项目中使用Security

新增依赖(在你的pom.xml中添加):

复制代码
 <!-- Security依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- JSON处理工具类 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.36</version>
        </dependency>

自定义配置类SpringSecurityConfig

  1. 我们需要在cn.tedu.ivos.base 包下新建一个security 包

  2. 在 security 包下创建一个自定义配置类 SpringSecurityConfig

  1. 这个配置类需要继承WebSecurityConfigurerAdapter
  • SpringSecurity框架提供了WebSecurityConfigurerAdapter安全基类

  • 该类提供了默认的安全配置,当我们的自定义类继承该类时,实际上在创建一个配置Bean

  • 这个Bean会被Spring自动检测到并用来定制我们自己的安全设置

  • 通过继承可以大大简化安全配置,而且重写 configure(HttpSecurity http)方法可以定制化内容

复制代码
package cn.tedu.ivos.base.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

//表示这是一个配置类,交由Spring容器管理
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

}

设置请求放行的处理方案(登录后端改造)

SpringSecurity基础安全配置1

重写configure(HttpSecurity http)进行配置

这些配置组合起来,创建了一个基础的安全策略,其中大部分资源需要认证,登录页面对所有人开放,且使用HTTP基本认证和自定义的登录成功/失败处理器

复制代码
package cn.tedu.ivos.base.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

//表示这是一个配置类,交由Spring容器管理
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);//这个表示调用父类的实现,我们不需要
        http.csrf().disable() // 禁用CSRF(跨站请求伪造)保护
                .httpBasic() // 配置HTTP基本认证
                .and().authorizeRequests() // 配置请求授权,默认禁用所有请求
                .antMatchers().permitAll() // 对指定的资源不进行权限检查,允许所有用户访问
                .anyRequest().authenticated() //对其他所有请求要求用户必须认证通过
                .and().formLogin() // 配置表单登录,默认拦截的登录请求地址为/login
                .successHandler(authenticationSuccessHandler) //设置认证成功处理器
                .failureHandler(authenticationFailureHandler) //设置认证失败处理器
                .permitAll() //允许所有用户进行登录尝试
        ;
    }
}
自定义的认证成功处理器CustomAuthenticationSuccessHandler

当用户成功通过认证后,会调用这个处理器的onAuthenticationSuccess方法

复制代码
package cn.tedu.ivos.base.security;

import cn.tedu.ivos.base.response.JsonResult;
import cn.tedu.ivos.user.mapper.UserMapper;
import cn.tedu.ivos.user.pojo.vo.UserVO;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Service;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
 * 自定义的认证成功处理器
 * 当用户成功通过认证后,会调用这个处理器的onAuthenticationSuccess方法
 * */
@Slf4j
@Service
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Autowired
    UserMapper userMapper;
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //可以根据我们的业务需要编写认证成功后的逻辑
        log.debug("认证成功");
        //从认证信息中获取用户名信息
        String username = authentication.getName();
        //根据用户名查询用户信息
        UserVO userVO = userMapper.selectByUsername(username);
        //设置响应的字符编码和内容类型,确保前端能正确解析JSON格式的数据
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");
        //将查询到的用户信息封装成JSON格式,写入响应中返回给前端
        response.getWriter().write(JSON.toJSONString(JsonResult.ok(userVO)));
    }
}
自定义的认证失败处理器CustomAuthenticationFailureHandler

当用户认证失败后,会调用这个处理器的onAuthenticationFailure方法

复制代码
package cn.tedu.ivos.base.security;

import cn.tedu.ivos.base.response.JsonResult;
import cn.tedu.ivos.base.response.StatusCode;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Service;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
 * 自定义的认证失败处理器
 * 当用户认证失败后,会调用这个处理器的onAuthenticationFailure方法
 * */
@Slf4j
@Service
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        //可以根据我们的业务需要编写认证失败后的逻辑
        log.debug("认证失败");
        //设置响应的字符编码为UTF-8,确保传输的数据在客户端能够正确解析
        response.setCharacterEncoding("UTF-8");
        //设置响应的内容类型为application/json,指定客户端应以JSON格式解析响应数据
        //同时指定字符集为UTF-8,与前面的设置保持一致
        response.setContentType("application/json;charset=UTF-8");
        //将用户名错误的响应结果转换为JSON格式,并写入响应流
        //JsonResult封装了状态码和可能的错误信息,这里使用StatusCode.USERNAME_ERROR表示用户名错误的特定状态码
        response.getWriter().write(JSON.toJSONString(new JsonResult(StatusCode.USERNAME_ERROR)));
    }
}
SpringSecurity基础安全配置2

重写configure(AuthenticationManagerBuilder auth) 方法

复制代码
package cn.tedu.ivos.base.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

//表示这是一个配置类,交由Spring容器管理
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    CustomAuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    CustomAuthenticationFailureHandler authenticationFailureHandler;
    @Autowired
    CustomAuthenticationProvider authenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);//这个表示调用父类的实现,我们不需要
        http.csrf().disable() // 禁用CSRF(跨站请求伪造)保护
                .httpBasic() // 配置HTTP基本认证
                .and().authorizeRequests() // 配置请求授权,默认禁用所有请求
                .antMatchers().permitAll() // 对指定的资源不进行权限检查,允许所有用户访问
                .anyRequest().authenticated() //对其他所有请求要求用户必须认证通过
                .and().formLogin() // 配置表单登录,默认拦截的登录请求地址为/login
                .successHandler(authenticationSuccessHandler) //设置认证成功处理器
                .failureHandler(authenticationFailureHandler) //设置认证失败处理器
                .permitAll() //允许所有用户进行登录尝试
        ;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
        auth.authenticationProvider(authenticationProvider);
    }
}

后续稍后更新....

相关推荐
奋进的芋圆2 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin2 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20052 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉2 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国2 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882483 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈3 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_993 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹3 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理
专注_每天进步一点点3 小时前
【java开发】写接口文档的札记
java·开发语言