Spring Security详细学习第一篇

Spring Security

  • 前言
  • Spring Security
    • 入门编辑
    • Spring Security底层原理
      • UserDetailsService接口
      • PasswordEncoder接口
    • 认证
      • 登录
      • 校验
      • 密码加密存储
      • 退出登录

前言

本文是作者学习三更老师的Spring Security课程所记录的学习心得和笔记知识,希望能帮助到大家

Spring Security

Spring Security基于Spring框架,提供了‘一套Web应用安全性的完整解决方案
Web应用安全性包括用户认证和用户授权是SpringSecurity的核心功能

  • 用户认证

系统认为用户是否能登录

  • 用户授权

判断用户是否有权限去做某些事情

入门编辑

第一步:搭建SpringBoot环境
第二步:导入相关依赖

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

编写一个测试类创建项目

@RestController
public class logincontroller {@GetMapping("/hello")public String vos(){return "Hello,security";}
}

启动项目后会发现需要进行登录认证
在这里插入图片描述
默认用户名:user
密码:
在这里插入图片描述

Spring Security底层原理

SpringSecurity的底层就是一个过滤器链
FilterSecurityInterceptor:是一个方法级的权限过滤器,基本位于过滤链的最底层
ExceptionTranslationFilter:是一个异常过滤器,用来处理在认证授权过程中抛出的异常
UsernamePasswordAuthenticationFilter:对/login的POST请求做拦截,校验表单中的用户名,密码

UserDetailsService接口

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

PasswordEncoder接口

数据加密接口,用于返回User对象里面密码加密
通过BCryptPasswordEncorder 对象对密码进行加密

认证

认证流程:
在这里插入图片描述

在这里插入图片描述
在前端发送携带用户登录信息的请求的时候,会到达UsernamePasswordAuthenticationFilter过滤器当中,过滤器将用户信息封装成一个Authentication对象,其中只存在用户名和密码,然后通过调用方法aythenticate一步一步向下认证,最后通过用户名在内存中进行查找,把对应的信息封装到UserDetils对象当中去,返回的时候通过PasswordEncoder对比密码,正确返回,这时默认的用户登录的流程。
我们一般采用的是在数据库中进行查询对应的用户信息,如果查询正确生成JWT信息返回给前端界面,此处我们可以自己创建一个controller类代替UsernamePasswordAuthenticationFilter过滤器,在最后可以自定义UserDetailsService的实现类完成在数据库中的查询

这是生成一个JWT的过程,那么如何去校验JWT信息:
创建一个jwt认证过滤器(获取token,解析token,获取userid,封装Authentication对象存入SecurityContextHolder)

整体的认证思路:
登录:
一:自定义登录接口
调用ProviderManager的方法进行认证,如果认证通过生成jwt
把用户信息存入到redis中
二:自定义UserDetilsService
在这个实现中去查询数据库
校验:
一:定义jwt认证过滤器
获取token
解析token获取其中的userid
从redis中获取用户信息
存入到securityContextHolder

登录

自定义UserDetilsService方法:

@Service
public class userdetilservice implements UserDetailsService {@Autowiredprivate Usermapper usermapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//查询用户信息LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(User::getUsername,username);org.apache.catalina.User user = usermapper.selectOne(lambdaQueryWrapper);if(Objects.isNull(user)){throw new RuntimeException("用户名或者密码错误");}return null;}
}

这里是要将信息封装到UserDetils中,我们需要创建一个实体类继承UserDetils

@Data
@NoArgsConstructor
@AllArgsConstructor
public class userdetilsimpl implements UserDetails {private User user;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return null;}@Overridepublic String getPassword() {return user.getAge();}@Overridepublic String getUsername() {return user.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}}

运行测试,在进行运行的时候会报出,passwordEncoder的配对的值为null,这时我们需要在数据库的密码数据中加入前缀{noop},这样表示该密码进行明文保存

  • 自定义登录接口

将AuthenticationManager注入到容器当中
在上述所讲的配置类中继承的WebsecurityConfigurerAdapter中可以重写方法完成AuthenticationManager的配置进行用户认证

    @Bean	public AuthenticationManager authenticationManager() throws Exception{return super.authenticationManagerBean();}

通过三层架构完善登录功能:在service的实现层impl中注入AuthenticationManager
封装之后可以通过它所提供的方法:authenticate进行认证,参数需要一个authentication对象,由于它是一个接口但是我们的框架中提供了它的实现对象,通过登录的用户名和密码可以创建一个authentication对象


@Service
public class loginserviceimpl implements loginservice {@Autowiredprivate AuthenticationManager authenticationManager;@Overridepublic void login(User user) {//进行用户认证//在登录之后将用户名和密码封装成一个Authentiaion对象//UsernamePasswordAuthenticationToken us=new UsernamePasswordAuthenticationToken(user.getUsername(),user.getAge());Authentication authenticate = authenticationManager.authenticate(us);//判断是否认证通过if(Objects.isNull(authenticate)){throw  new RuntimeException("登陆失败");}//如果通过了使用userid生成一个jwt,jwtUser user1 = (User) authenticate.getPrincipal();String string = user1.getId().toString();String jwt=JwtUtil.createJWT(string);Map<String,String> map=new HashMap<>();map.put("token",jwt);return new ResponseResult(200,"登录成功",map);}
}

校验

创建一个过滤器,之前的javaWeb讲解中过滤器都实现Filter,在这里我们继承OncePerRequestFilter就可,这样会使得前端请求来的请求只经过该过滤器一次
过滤器代码:

@Component
public class AuthonJwtfilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {//获取tokenString token = httpServletRequest.getHeader("token");//判断token是否为空if(!StringUtils.hasText(token)){//放行filterChain.doFilter(httpServletRequest,httpServletResponse);return;}// 解析tokentry {Claims claims=JwtUtil.parseJWT(token);String id=claims.getSubject();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("token非法");}//从redis中获取用户信息String rediskey="login:"+id;User user=redisCache.getCacheObject(rediskey);if(!Objects.isNull(user)){throw new RuntimeException("用户未登录");}//存入SecurityContextHolderUsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(user,null,null);SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);//放行filterChain.doFilter(httpServletRequest,httpServletResponse);}
}

完成后需要在配置类中将jwt过滤器放在过滤链中:
在配置类的配置方法configure中配置

http.addFilterBefore(jwtAuthenticationTokenFilter,usernamePasswordAunthencationFilter.class);

密码加密存储

实际项目中我们不会将密码明文保存在数据库中,默认的PasswordEncoder要求数据库中的密码格式为:{id}password根据id进行判断加密方式
我们一般所用的是SpringSAecurity为我们提供的BCryptPasswordEncorder
我们将BCryptPasswordEncorder注入容器中,我们就可以根据passwordEncoder进行密码判断

我们需要进行Spring Security进行配置类:

@Configuration
public class securityconfig extends WebSecurityConfigurerAdapter {@Bean//创建BCryptPasswordEncoder注入容器public PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}

我们可以使用encode方法将明文密码进行加密
可以使用matches方法将密码与加密后的方法判断是否匹配

    @Testpublic void  TestBC(){BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();//对数据进行加密//使用盐和加密String encode = bCryptPasswordEncoder.encode("123456");bCryptPasswordEncoder.matches("1234","加密之后的密文");}
}

退出登录

如何退出登录:
我们只需要定义一个登录接口,然后获取securityContextHolder中的认证信息,删除redis中的数据,这样就会退出登录
也是通过三层架构进行退出登录操作,在服务实现类中:


public class zhuxiaoimpl {public ResponseResult logout(){UsernamePasswordAuthenticationToken authenticationToken= (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();User user= (User) authenticationToken.getPrincipal();String string = user.getId().toString();//删除redis中的值redisCache.delete(string);return new ResponseResult(200,"注销成功");}
}
}

注意,在其中还应该删除SecurityContextHolder中保存的值,要不然就算登出,还是会保持认证状态的

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

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

相关文章

使用Java调用音乐开放API,并进行播放

使用Java调用音乐开放API&#xff0c;并进行播放 背景描述 电脑没有下载音乐软件&#xff0c;使用网页播放又不太方便&#xff0c;所有就想着使用Java语言直接调用音乐开放API&#xff0c;然后进行播放音乐。 具体代码如下&#xff0c;包含了注释 package com.lowkey.comple…

吴恩达<用于LLM应用程序开发的LangChain> L1-Model_prompt_parser

问题预览/关键词 课程地址如何获取openAI的API Key如何根据日期设置不同模型?如何调用OpenAI的API?如何使用OpenAI的API&#xff1f;langchain如何抽象OpenAI的API接口&#xff1f;langchain如何创建提示词模板并查看模板内容&#xff1f;langchain如何使用提示词模板生成提…

Redis中的BigKey

Redis中的BigKey 文章目录 Redis中的BigKey什么是BigKey&#xff1f;BigKey的危害找到Bigkey删除BigKey优化BigKeyBigKey对持久化的影响对AOF日志的影响对AOF重写和RDB的影响 什么是BigKey&#xff1f; 大 key 并不是指 key 的值很大&#xff0c;而是 key 对应的 value 很大。…

2024华中杯A题完整1-3问py代码+完整思路16页+后续参考论文

A题太阳能路灯光伏板朝向问题 &#xff08;完整版资料文末获取&#xff09; 第1小问&#xff1a;计算每月15日的太阳直射强度和总能量 1. 理解太阳直射辐射和光伏板的关系**&#xff1a;光伏板接收太阳辐射并转化为电能&#xff0c;直射辐射对光伏板的效率影响最大。 2. 收集…

[Vision Board创客营]学习片上Flash移植FAL

文章目录 [Vision Board创客营]学习片上Flash移植FAL介绍环境搭建使用组件测试porbeerasewriteread 结语 [Vision Board创客营]学习片上Flash移植FAL 水平较菜&#xff0c;大佬轻喷。&#x1f630;&#x1f630;&#x1f630; 介绍 &#x1f680;&#x1f680;Vision-Board 开…

Leetcode算法训练日记 | day29

一、递增子序列 1.题目 Leetcode&#xff1a;第 491 题 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&…

“低价竞争”仍在继续,分期免息成商家新武器

近日&#xff0c;在京东618商家生态伙伴大会上&#xff0c;京东推出各项政策&#xff0c;尽全力让所有合作伙伴赢在京东618、赢在京东。京东金融也将在618大促期间&#xff0c;为各位商家带来极具竞争力的金融产品和大促政策。 举例来说&#xff0c;大促期间&#xff0c;“京东…

基于SSM+Jsp+Mysql的文物管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

js高级 笔记02

目录 01 object提供的一些静态方法 02 词法作用域 03 作用域链 04 arguments的使用 05 开启严格模式 06 高阶函数 07 闭包 01 object提供的一些静态方法 Object.create() 对象继承 Object.assign(对象1,对象2) 对象合并 可以将对象2 里面的可枚举属性和自身的属性合并到…

Matlab r2023b Simulink 给子系统添加封面

写这篇记录的原因是&#xff0c;r2023b版本里改动了自定义封面的界面&#xff0c;而我是一个新手小白&#xff0c;零基础&#xff0c;探索一天之后发现实现方法。最终效果如图&#xff1a; 步骤1&#xff1a;打开软件&#xff0c;点击Simulink&#xff0c;再打开含有子系统的工…

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题7

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题7 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发 任务书&#xff0c;赛题&#xff0c;解析等资料&#xff0c;知识点培训服务 添加博主wx&#xff1a;liuliu548…

SpringSecurity源码4

SecurityContext.class 当前线程关联的最小安全信息&#xff0c;提供Authentication的get/set方法 SecurityContextHolder.class SecurityContext的持有器 // 全部委托给策略类public static void setContext(SecurityContext context) {strategy.setContext(context);}public …

FFmpeg: 自实现ijkplayer播放器--03UI界面设计

文章目录 UI设计流程图UI设计界面点击播放功能实现 UI设计流程图 UI设计界面 主界面 控制条 播放列表 画面显示 标题栏 设置界面 提示框 点击播放功能实现 槽函数实现&#xff1a; connect(ui->ctrlBarWind, &CtrlBar::SigPlayOrPause, this, &Main…

[渗透测试学习] TwoMillion-HackTheBox

TwoMillion-HackTheBox 信息搜集 nmap扫描一下 nmap -sV -v 10.10.11.221扫描结果 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0) 80/tcp open http nginx 3851/tcp f…

4.18作业

顺序栈&#xff1a; #include "seq_stack.h" seq_p creat_stack() //从堆区申请顺序栈的空间 {seq_p S(seq_p)malloc(sizeof(seq_stack));if(SNULL){printf("空间申请失败\n");return NULL;}bzero(S->data,sizeof(S->data));S->top-1;return S; …

多任务学习,在共享层,究竟在共享什么?

在多任务学习中&#xff0c;共享层所共享的主要是网络结构和参数。具体来说&#xff0c;当多个任务在共享层进行参数硬共享时&#xff0c;它们使用的是相同的网络结构&#xff08;例如三层全连接神经网络&#xff09;&#xff0c;并且这些网络层的权重&#xff08;weights&…

深入解析Nacos配置中心的动态配置更新技术

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在微服务架构中&#xff0c;配置管理变得尤为关键。Nacos&#xff0c;作为一个开源的、易于使用的、功能丰富的平台&#xff0c;为…

【MATLAB源码-第28期】基于matlab的16QAM定时同步仿真,采用gardner算法,Costa锁相环。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 正交幅度调制&#xff08;QAM&#xff0c;Quadrature Amplitude Modulation&#xff09;是一种在两个正交载波上进行幅度调制的调制方式。这两个载波通常是相位差为90度&#xff08;π/2&#xff09;的正弦波&#xff0c;因此…

02 - Git 之命令 + 删除 + 版本控制 + 分支 + 标签 + 忽略文件 + 版本号

1 Git相关概念 1.1 以下所谈三个区&#xff0c;文件并不只是简单地在三个区转移&#xff0c;而是以复制副本的方式转移 使用 Git 管理的项目&#xff0c;拥有三个区域&#xff0c;分别是 Working area工作区&#xff08;亦称为 工作树Working Tree&#xff09;、stage area …

[渗透测试学习] Monitored-HackTheBox

Monitored-HackTheBox 信息搜集 nmap扫描一下端口 nmap -sV -sC -v --min-rate 1000 10.10.11.248扫描结果如下 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0) 80/tcp open http Apache httpd …