【SpringSecurity】五、UserDetails接口和UserDetailsService接口

news2025/5/14 1:07:22

文章目录

  • 1、SpringSecurity原理
  • 2、UserDetails接口
  • 3、UserDetailService接口
  • 4、权限配置

1、SpringSecurity原理

Spring Security是做安全访问控制,对所有进入系统的请求进行拦截,并做校验,这可以通过Filter或者AOP实现,Spring Security靠Filter。

在这里插入图片描述

  • 初始化Spring Security时,创建一个名为SpringSecurityFilterChain的Servlet过滤器,类型为org.springframework.security.web.FilterChainProxy,它实现了javax.servlet.Filter,因此外部的请求会经过此类
  • FilterChainProxy是一个代理,真正起作用的是FilterChainProxy中SecurityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理
  • 这些Filter不负责认证或者授权,而是交给认证管理器(AuthenticationManager)和决策管理器(AccessDecisionManager)进行处理。(过滤器嘛,就是拦截下,获取点东西、修改点东西、干点操作)

Spring Security功能的实现就是一系列过滤器链相互配合。

在这里插入图片描述

  • SecurityContextPersistenceFilter 这个Filter是整个拦截过程的入口和出口,也就是第一个和最后一个拦截器。会在请求开始时从配置好的 SecurityContextRepository 中获取 SecurityContext,然后把它设置给 SecurityContextHolder。在请求完成后将 SecurityContextHolder 持有的 SecurityContext 再保存到配置好的 SecurityContextRepository,同时清除 securityContextHolder 所持有的 SecurityContext;

  • UsernamePasswordAuthenticationFilter 用于处理来自表单提交的认证,该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的 AuthenticationSuccessHandler 和 AuthenticationFailureHandler,这些都可以根据需求做相关改变;(这些处理器的逻辑可自定义,重新实现一下这个处理器)

  • ExceptionTranslationFilter 能够捕获来自 FilterChain 所有的异常,并进行处理。但是它只会处理两类异常:AuthenticationException 和 AccessDeniedException,其它的异常它会继续抛出。

  • FilterSecurityInterceptor 是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问

SpringSecurity的执行流程:

在这里插入图片描述

  • 用户提交用户名密码,被安全过滤器链中的UsernamePasswordAuthenticationFilter过滤器拿到,并封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类
  • 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
  • 认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication实例
  • SecurityContextHolder安全上下文容器将上一步填充了信息的Authentication,通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中
  • 以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它的实现类为ProviderManager
  • 而Spring Security支持多种认证方式,因此ProviderManager维护着一个List列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。而web表单的对应的AuthenticationProvider实现类为DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。当UserDetailsService接口的loadUserByUsername()方法获取到的User Details对象中的密码和Authentication中的密码一致时,认证成功,最后AuthenticationProvider将UserDetails填充至Authentication

2、UserDetails接口

看完上面的UserDetails对象和UserDetailsService接口的loadUserByUsername方法后,再看之前在内存中定义用户,是这样的:

UserDetails user2 = User.builder()
        .username("liu")
        .password(passwordEncoder().encode("123456"))
        .authorities("teacher:add","teacher:update")
        .roles("teacher")
        .build();

查看User类的源码,其实现了UserDetails接口,因此上面才可以直接创建User对象。

在这里插入图片描述

接下来自己定义一个用户类SecurityUser类,也去实现UserDetails接口,重写UserDetails接口方法时,直接写死一个用户信息,一会儿new这个自定义的SecurityUser类,也就和上面的User.builder一个意思。

public class SecurityUser implements UserDetails {
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;   //未给权限
    }

    @Override
    public String getPassword() {
        //明文为123456
        //return "$2a$10$KyXAnVcsrLaHMWpd3e2xhe6JmzBi.3AgMhteFq8t8kjxmwL8olEDq";
        return new BCryptPasswordEncoder().encode("123456");
    }

    @Override
    public String getUsername() {
        return "liu";
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

UserDetails 接口的7个方法如下图:

方法名作用
getAuthorities()获取当前用户对象所具有的角色信息
getPassword()获取当前用户对象的密码
getUsername()获取当前用户对象的用户名
isAccountNonExpired()当前账户是否未过期
isAccountNonLocked()当前账户是否未锁定
isCredentialsNonExpired()当前账户密码是否未过期
isEnabled()当前账户是否可用

3、UserDetailService接口

UserDetails的用户对象建好了,继续看之前在内存中创建用户的实现思路:

InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
userDetailsManager.createUser(user1);
userDetailsManager.createUser(user2);

InMemoryUserDetailsManager类实现了UserDetailsManager接口,UserDetailsManager接口又继承了UserDetailService接口:

在这里插入图片描述

自己新建一个类UserServiceImpl去实现UserDetailService接口。重写loadUserByUsernam方法,并当用户名等于自定义的SecurityUser对象中的用户名时,返回SecurityUser对象。

@Service
public class UserServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SecurityUser securityUser= new SecurityUser();
        if(username==null || !username.equals(securityUser.getUsername())){
            throw new UsernameNotFoundException("该用户不存在");
        }
        return securityUser;
    }
}


以上其实是自己玩了下5.6两步:

在这里插入图片描述

重启服务,登录下,一切正常。

在这里插入图片描述

4、权限配置

上面自定义的SecurityUser类中,关于权限的方法返回null,写个接口返回认证信息,可以看到权限字段确实为null:
在这里插入图片描述
在这里插入图片描述

加权:

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
       GrantedAuthority g1=()->"student:query"; //使用lambda表达式
	   //GrantedAuthority g1=new SimpleGrantedAuthority("student:query");
       List<GrantedAuthority> grantedAuthorityList=new ArrayList<>();
       grantedAuthorityList.add(g1);
       return grantedAuthorityList;
    }

顺便使用@PreAuthorize注解方便后面看下效果:

@RestController
@RequestMapping("/student")
public class StudentController {
    @GetMapping("/query")
    @PreAuthorize("hasAuthority('student:query')")
    public String queryInfo(HttpServletRequest request){
        return "I am a student,My name is XXX";
    }
}

重启后查看认证信息:

在这里插入图片描述
在这里插入图片描述

梳理完UserDetails和UserDetailsService接口之间的流程和细节,方便后面理解SpringSecurity基于数据库认证。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/918586.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 条件查询 Emoji 表情符号却返回多条数据【包含其它表情符号】的问题解决 - COLLATION 字符序的选择

1、问题出现 在APP客户端输入搜索文章的关键字时&#xff0c;不小心输入来了一个 emoji 表情符号&#xff0c;提示出错了&#xff0c;在后台查询错误日志信息&#xff0c;提示查询出现了2条相同的记录&#xff1a; Caused by: org.hibernate.NonUniqueResultException: query …

【Java 高阶】一文精通 Spring MVC - 数据格式化器(六)

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

python - 编程中【工厂模式】和【单例模式】区别以及代码示例详解

一. 概念 工厂模式和单例模式都是面向对象编程中常用的设计模式。 工厂模式&#xff08;FactoryPattern&#xff09;&#xff1a;是一种创建型模式&#xff0c;它提供了一种方法来创建对象&#xff0c;而不需要暴露对象的创建逻辑。这种模式通过定义一个工厂类&#xff0c;通…

优化生产流程:数字化工厂中的OPC UA分布式IO模块应用

背景 近年来&#xff0c;为了提升在全球范围内的竞争力&#xff0c;制造企业希望自己工厂的机器之间协同性更强&#xff0c;自动化设备采集到的数据能够发挥更大的价值&#xff0c;越来越多的传统型工业制造企业开始加入数字化工厂建设的行列&#xff0c;实现智能制造。 数字化…

归一化的作用,sklearn 安装

目录 归一化的作用&#xff1a; 应用场景说明 sklearn 准备工作 sklearn 安装 sklearn 上手 线性回归实战 归一化的作用&#xff1a; 归一化后加快了梯度下降求最优解的速度; 归一化有可能提高精度(如KNN) 应用场景说明 1&#xff09;概率模型不需要归一化&#xff…

强化历程5-Java并发系列(2023.8.23)

文章目录 强化历程5-Java并发系列(2023.8.23)1 Java多线程1.1 Java中多线程有几种实现方式&#xff1f;1.2 那么Runnable和Callable都可以实现多线程&#xff0c;他们有什么区别?1.3 采用实现Runnable和Callable接口方式和采用继承Thread类方式各有什么好处?1.4 Java如何停止…

【数据结构与算法】—— 手撕红黑树

目录 &#xff08;一&#xff09;红黑树的定义 1、红黑树的引入 2、红黑树的概念 3、红黑树的性质 &#xff08;二&#xff09;红黑树的操作 1、红黑树节点的定义 2、红黑树的插入操作 1️⃣ 思路 2️⃣ 代码实现 3、红黑树的删除操作&#xff08;了解&#xff09; …

Compose - 基本使用

一、概念 1.1 Compose优势 由一个个可以组合的Composable函数拼成界面&#xff0c;方便维护和复用。布局模型不允许多次测量&#xff0c;提升了性能。Compose可以和View互操作&#xff08;相互包含对方&#xff09;。 1.2 声明式UI APP展示的数据绝大多数不是静态数据而是会…

An easy problem

一、题目 we define f(A) 1, f(a) -1, f(B) 2, f(b) -2, … f(Z) 26, f(z) -26; Give you a letter x and a number y , you should output the result of yf(x). Input On the first line, contains a number T.then T lines follow, each line is a case.each case …

多线程基础篇(包教包会)

文章目录 一、第一个多线程程序1.Jconsole观察线程2.线程休眠-sleep 二、创建线程三、Thread类及常见方法1. Thread 的常见构造方法2. Thread 的几个常见属性3. 启动线程 - start4. 中断线程5. 等待一个线程 四、线程状态五、线程安全问题(synchronized)&#xff08;重点&#…

基于React实现日历组件详细教程

前言 日历组件是常见的日期时间相关的组件&#xff0c;围绕日历组件设计师做出过各种尝试&#xff0c;展示的形式也是五花八门。但是对于前端开发者来讲&#xff0c;主要我们能够掌握核心思路&#xff0c;不管多么奇葩的设计我们都能够把它做出来。 本文将详细分析如何渲染一…

windows系统activemq一键安装启动

前言 官网下载的mq提供了启动和卸载服务器的脚本&#xff0c;但是安装的时候不会自动启动服务&#xff0c;需要去手动比较麻烦&#xff0c;执行脚本的时候也需要去右键选择管理员执行做起来比较啰嗦。 优化方案 修改脚本权限为自动判断并获取 在脚本开头加入下面的代码 …

店铺收款系统开源_商城收款分账系统_OctShop

近来&#xff0c;很多客户对OctShop店铺收款分账系统有很大的需求&#xff0c;下面详细介绍一下&#xff0c;门店收款分账系统是什么&#xff0c;以及其作用与意义是什么&#xff1f; 店铺收款分账系统实质上是一个解决门店各种收款场景&#xff0c;如&#xff1a;扫码付款&…

零基础学习,初学者也能轻松制作高质量母婴行业小程序

现如今&#xff0c;随着移动互联网的发展&#xff0c;小程序成为了各行各业的新宠。对于母婴行业来说&#xff0c;拥有一个功能完善、用户友好的小程序&#xff0c;无疑是提升企业形象和服务质量的重要一环。然而&#xff0c;对于初学者来说&#xff0c;如何轻松掌握母婴行业小…

微服务中间件--http客户端Feign

http客户端Feign http客户端Feigna.Feign替代RestTemplateb.自定义Feign的配置c.Feign的性能优化d.Feign的最佳实践分析e.Feign实现最佳实践(方式二) http客户端Feign a.Feign替代RestTemplate 以前利用RestTemplate发起远程调用的代码&#xff1a; String url "http:…

【面试题】你理解中JS难理解的基本概念是什么?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 作用域与闭包 作用域 作用域是当前的执行上下文&#xff0c;值和表达式在其中“可见”或可被访问。如果一个变量或表达式不在当前的作用域中&#xff0…

SpringBoot利用ConstraintValidator实现自定义注解校验

一、前言 ConstraintValidator是Java Bean Validation&#xff08;JSR-303&#xff09;规范中的一个接口&#xff0c;用于实现自定义校验注解的校验逻辑。ConstraintValidator定义了两个泛型参数&#xff0c;分别是注解类型和被校验的值类型。在实现ConstraintValidator接口时&…

【业务功能篇77】微服务-OSS对象存储-上传下载图片

3. 图片管理 文件存储的几种方式 单体架构可以直接把图片存储在服务器中 但是在分布式环境下面直接存储在WEB服务器中的方式就不可取了&#xff0c;这时我们需要搭建独立的文件存储服务器。 3.1 开通阿里云服务 针对本系统中的相关的文件&#xff0c;图片&#xff0c;文本等…

JavaSE 数组

定义&#xff1a; int []arr; int arr[]; 初始化 // 完整格式 int arr[] new int[]{1, 2, 3}; // 简单格式 int arr[] {1, 2, 3}; 数组的元素访问、遍历 按照下标访问即可。数组的长度函数为 arr.length()。idea快速生成遍历的方法&#xff1a;数组名.fori 静态初始化 &a…

9.Sentinel哨兵

1.Sentinel Sentinel&#xff08;哨兵&#xff09;是由阿里开源的一款流量控制和熔断降级框架&#xff0c;用于保护分布式系统中的应用免受流量涌入、超载和故障的影响。它可以作为微服务架构中的一部分&#xff0c;用于保护服务不被异常流量冲垮&#xff0c;从而提高系统的稳定…