SpringSecurity

目录

一、SpringSecurity 简介

1.1 概念

1.2 原理

1.3 核心组件简介

1.4 验证和授权的过程及本质

二、简单应用

2.1 引入依赖

2.2 访问页面

三、认证相关 API

3.1 UserDetailsService 详解

3.2 PasswordEncoder 密码编码器接口详解

3.3 自定义认证逻辑

3.3.1 编写配置类

3.3.2 编写认证服务实现类

3.3.3 测试

3.4 自定义登录页面

3.4.1 编写登录页面

3.4.2 修改配置类​​​​​​​

​3.4.3 编写控制器

3.5 认证过程其他常用配置

3.5.1 失败跳转

3.5.2 自定义请求中的用户名和密码

3.5.3 自定义登录成功处理器

3.5.4 自定义登录失败处理器

四、 授权相关 API 

4.1 url 匹配规则详解

4.1.1 anyRequest()

4.1.2 antMatcher() 

4.2 权限控制方法详解

4.2.1 permitAll()

4.2.2 authenticated()

4.2.3 anonymous()

4.2.4 denyAll()

4.2.5 rememberMe()

4.2.6 fullyAuthenticated()

4.3 角色权限判断

4.3.1 hasAuthority(String)

4.3.2 hasAnyAuthority(String ...)

4.3.3 hasRole(String)

​4.3.4 hasAnyRole(String ...)

4.3.5 hasIpAddress(String)

4.4 自定义无权限 403 处理方案

4.4.1 新建处理器类

4.4.2 修改配置类

4.5 基于表达式的访问控制

4.5.1 使用 access()方法内置表达式

4.5.2 使用自定义方法

4.6 基于注解的访问控制

4.6.1 @Secured

4.6.2 @PreAuthorize/@PostAuthorize

4.6.3 添加@PreAuthorize

五、 其他功能

5.1 Remember Me 功能实现

5.1.1 引入依赖

5.1.2 修改核心属性文件添加数据源信息(4项)

5.1.3 编写配置类

5.1.4 修改 SecurityConfig 配置类

5.1.5 在客户端页面中添加复选框

5.1.6 设置 rememberme 有效时间

5.2 退出登录


一、SpringSecurity 简介

1.1 概念

Spring Security is a powerful and highly customizable authentication and access-control framework.

Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IoC,DI 和 AOP 功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。 Spring Security 的主要核心功能为 认证和授权,整个架构也是基于这两个核心功能去实现的。

1.2 原理

众所周知 想要对 Web 资源进行保护,最好的办法莫过于 Filter 和 Interceptor。
所以 SpringSecurity 在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。 如下为其主要过滤器    :

  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • LogoutFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • AnonymousAuthenticationFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • UsernamePasswordAuthenticationFilter
  • BasicAuthenticationFilter

1.3 核心组件简介

Spring Security bean 的核心类

  • SecurityContextHolder:提供对 SecurityContext 的访问
  • SecurityContext,:持有 Authentication 对象和其他可能需要的信息
  • AuthenticationManager: 其中可以包含多个 AuthenticationProvider
  • ProviderManager:对象为 AuthenticationManager 接口的实现类
  • AuthenticationProvider:主要用来进行认证操作的类 调用其中的authenticate()方法去进行认证操作
  • Authentication:Spring Security 方式的认证主体
  • GrantedAuthority:对认证主题的应用层面的授权,含当前用户的权限信息,通常使用角色表示
  • UserDetails:构建 Authentication 对象必须的信息,可以自定义,可能需要访问 DB 得到
  • UserDetailsService:通过username构建UserDetails对象,通过loadUserByUsername 根据 userName 获取UserDetail对象(可以在这里基于自身业务进行自定义的实现    如通过数据库,xml,缓存获取等)

1.4 验证和授权的过程及本质

用户一次完整的登录验证和授权,是一个请求经过 层层拦截器从而实现权限控制,整个 web 端配置为 DelegatingFilterProxy,它并不实现真正的过滤,而是所有过滤器链的代理类,真正执行拦截处理的是由 spring 容器管理的各个filter bean 组成的 filterChain。

二、简单应用

2.1 引入依赖

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

2.2 访问页面

导入 spring-boot-starter-security 启动器后,Spring Security 已经生效,默认拦截全部请求,如果用户没有登录,跳转到内置登录页面。
在resources下建立static目录,然后再static目录下创建index.html
在浏览器输入:http://localhost:8080后会显示下面页面

 默认的 username 为 user,password 打印在控制台中。以上为默认值。

在浏览器中输入账号和密码后登录成功后会显示 index.html 页面内容。

 

三、认证相关 API

3.1 UserDetailsService 详解

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

 该接口抽象方法的返回值 UserDetails 是一个接口,定义如下:

 要想返回 UserDetails 的实例就只能返回接口的实现类。SpringSecurity 中提供了如下的实例。对于我们只需要使用里面的 User 类即可。
注意 User 的全限定路径是:
org.springframework.security.core.userdetails.User 此处经常和系统中自己开发的 User 类弄混。

在 User 类中提供了很多方法和属性:

构造方法参数说明:

  1. username:用户名
  2. password:密码
  3. authorities:用户具有的权限。此处不允许为 null

此处的用户名应该是客户端传递过来的用户名。而密码应该是从数据库中查询出来的密码。Spring Security 会根据 User 中的 password 和客户端传递过来的 password 进行比较。如果相同则表示认证通过,如果不相同表示认证失败。 authorities 里面的权限对于后面学习授权是很有必要的,包含的所有内容为此用户具有的权限,如有里面没有包含某个权限,而在做某个事情时必须包含某个权限则会出现 403 。通常都是通过AuthorityUtils.commaSeparatedStringToAuthorityList(“”) 来创建 authorities 集合对象的。参数是一个字符串,多个权限使用逗号分隔。

注意:
username 是客户端表单传递过来的数据。默认情况下参数名必须 username,否则无法接收。

3.2 PasswordEncoder 密码编码器接口详解

Spring Security 要求容器中必须有 PasswordEncoder 实例。所以当自定义登录逻辑时要求必须给容器注入 PaswordEncoder 的 bean 对象。

接口介绍:

  1. encode():把参数按照特定的解析规则进行解析。
  2. matches()验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。如果密码匹配,则返回 true;如果不匹配,则返回 false。第一个参数表示需要被解析的密码。第二个参数表示存储的密码。
  3. upgradeEncoding():如果解析的密码能够再次进行解析且达到更安全的结果则返回 true,否则返回 false。默认返回 false。

PaswordEncoder 实现类有很多:

比较常用的BCryptPasswordEncoder


BCryptPasswordEncoder 是 Spring Security 官方推荐的密码编码器,平时多使用这个编码器。
BCryptPasswordEncoder 是对 bcrypt 强散列方法的具体实现。是基于Hash算法实现的单向加密。可以通过 strength 控制加密强度,默认10。

示例代码:

package com.tjetc;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@SpringBootTest
public class MyTest {
    @Test
    public void test() {
        //1、创建BCryptPasswordEncoder对象
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        //2、把原始密码加密
        String encodePassword = encoder.encode("123456");
        System.out.println("123456密码加密后:" + encodePassword);
        //3、原始密码和加密后的密码进行比对
        boolean matches = encoder.matches("123456", encodePassword);
        System.out.println("是否匹配:" + matches);
    }
}

3.3 自定义认证逻辑

3.3.1 编写配置类

3.3.2 编写认证服务实现类

该类需要实现 UserDetailsService 接口

package com.tjetc.service.Impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 提供一个实现UserDetails接口的对象,包含:正确的用户名、密码、权限列表
     * loadUserByUsername   不比较用户传来的密码的正确性,比较交给spring security框架
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1、从数据库根据用户名查询username是否存在,
        //   没有用户抛出异常UsernameNotFoundException,
        //   有的话继续执行代码
        //   模拟查询,用户名不是admin,抛异常
        if (!"admin".equals(username)) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        //2、从数据库根据用户名查询正确的密码
        //   模拟正确密码   $2a$10$vdGrOfmKlfcVga4JCIwzJOpJYEpDC/kF1LQx3OcBNx2zph3YVfziK
        //   这个数据是passwordEncoder生成的
        String password = passwordEncoder.encode("123456");
        //3、从数据库查询用户的权限信息
        //   模拟:权限信息字符串,生成权限对象
        //   AuthorityUtils.commaSeparatedStringToAuthorityList   用途是  把用逗号分割的权限字符串转换成权限对象的集合
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        //4、返回UserDetails实现类对象(例如:User是security定义)
        User user = new User(username, password, authorities);
        return user;
    }
}

3.3.3 测试

重启项目,在浏览器中输入账号:admin,密码:123456。后可以正确进入到 index.html 页面。

           

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值