Spring Security入门

目录

1.简介         

与shiro对比

添加依赖

执行流程

2.UserDetailsService

User实现类

3.PasswordEncoder

BCryptPasswordEncoder

4.自定义登录逻辑

5.自定义登录界面

6.设置请求账户和密码的参数

7.自定义登陆处理器

成功

失败

8.判断

权限判断

角色判断

ip判断

9.基于注解开发

@Secured

@PreAuthorize/@PostAuthorize

10.记住我功能

导入依赖

自定义

11.未完待续...


1.简介         

Spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念,可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验证选项和授权策略,开发人员可以根据需要选择适合的方式。此外,Spring Security还提供了一些附加功能,如集成第三方身份验证提供商和单点登录,以及会话管理和密码编码等。总之,Spring Security是一个强大且易于使用的框架,可以帮助开发人员提高应用程序的安全性和可靠性。

与shiro对比

Apache Shiro是一个强大且易用的Java安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

ssm+shrio

springBoot+springSecurity

添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--web-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--test-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>

执行流程

2.UserDetailsService

通过传入的用户名来判断,如果要自定义逻辑来进行判断只需要实现UserDetailsService接口,而该接口又继承了UserDetails接口

public interface UserDetails extends Serializable {/*** Returns the authorities granted to the user. Cannot return <code>null</code>.* @return the authorities, sorted by natural key (never <code>null</code>)*/Collection<? extends GrantedAuthority> getAuthorities();/*** Returns the password used to authenticate the user.* @return the password*/String getPassword();/*** Returns the username used to authenticate the user. Cannot return* <code>null</code>.* @return the username (never <code>null</code>)*/String getUsername();/*** Indicates whether the user's account has expired. An expired account cannot be* authenticated.* @return <code>true</code> if the user's account is valid (ie non-expired),* <code>false</code> if no longer valid (ie expired)*/boolean isAccountNonExpired();/*** Indicates whether the user is locked or unlocked. A locked user cannot be* authenticated.* @return <code>true</code> if the user is not locked, <code>false</code> otherwise*/boolean isAccountNonLocked();/*** Indicates whether the user's credentials (password) has expired. Expired* credentials prevent authentication.* @return <code>true</code> if the user's credentials are valid (ie non-expired),* <code>false</code> if no longer valid (ie expired)*/boolean isCredentialsNonExpired();/*** Indicates whether the user is enabled or disabled. A disabled user cannot be* authenticated.* @return <code>true</code> if the user is enabled, <code>false</code> otherwise*/boolean isEnabled();}

User实现类

        这个user不是我们自定义的User类,他继承了UserDetails接口,通过客户端传入的username在去数据库匹配对应的密码,然后通过查询出来的密码与前端进行匹配

public User(String username, String password, boolean enabled, boolean accountNonExpired,boolean credentialsNonExpired, boolean accountNonLocked,Collection<? extends GrantedAuthority> authorities) {Assert.isTrue(username != null && !"".equals(username) && password != null,"Cannot pass null or empty values to constructor");this.username = username;this.password = password;this.enabled = enabled;this.accountNonExpired = accountNonExpired;this.credentialsNonExpired = credentialsNonExpired;this.accountNonLocked = accountNonLocked;this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
}

3.PasswordEncoder

public interface PasswordEncoder {/*** Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or* greater hash combined with an 8-byte or greater randomly generated salt.*/String encode(CharSequence rawPassword);//加密密码/*** Verify the encoded password obtained from storage matches the submitted raw* password after it too is encoded. Returns true if the passwords match, false if* they do not. The stored password itself is never decoded.* @param rawPassword the raw password to encode and match* @param encodedPassword the encoded password from storage to compare with* @return true if the raw password, after encoding, matches the encoded password from* storage*/boolean matches(CharSequence rawPassword, String encodedPassword);//原密码和加密密码进行匹配/*** Returns true if the encoded password should be encoded again for better security,* else false. The default implementation always returns false.* @param encodedPassword the encoded password to check* @return true if the encoded password should be encoded again for better security,* else false.*/default boolean upgradeEncoding(String encodedPassword) {return false;}}

BCryptPasswordEncoder

官方推荐的一个实现类,基于哈希算法进行加密

4.自定义登录逻辑

@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//1.模拟数据库查询用户名是否存在否则抛出异常UsernameNotFoundExceptionif(!"admin".equals(username)){throw new UsernameNotFoundException("用户名不存在!");}//2.把加密过的密码进行解析String password = passwordEncoder.encode("123");return new User(username,password,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));}
}

5.自定义登录界面

重定向时只能用@Controller,不能用@RestController

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder getPw(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin()//当发现是login时认为是登录,必须和表单提供的地址一致去执行UserDetailsServiceImpl.loginProcessingUrl("/login")//自定义登录界面.loginPage("/login.html")//登录成功后必须是post请求.successForwardUrl("/toMain")//登录失败后跳转.failureForwardUrl("/toError");//认证授权http.authorizeRequests()//登录失败放行不需要认证.antMatchers("/error.html").permitAll()//登录放行不需要认证.antMatchers("/login.html").permitAll()//所有请求都被拦截类似于mvc必须登录后访问.anyRequest().authenticated();//关闭csrf防护http.csrf().disable();}
}
/*** 页面跳转* @return*/@RequestMapping("/toMain")public String toMain(){return "redirect:main.html";}/*** 页面失败跳转* @return*/@RequestMapping("/toError")public String toError(){return "redirect:error.html";}

6.设置请求账户和密码的参数

登录的表单name为username和password与UsernamePasswordAuthenticationFilter中相对应,如果我们想要修改这个属性名可以通过usernameParameter()和passwordParameter()进行修改

public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";

7.自定义登陆处理器

由于前后端分离项目,页面跳转大多都在web浏览器中进行,这时successForwardUrl()和failureForwardUrl()方法就会失效,所以我们就要自定义方法进行实现且不能与successForwardUrl和failureForwardUrl共存

成功

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {private String url;public MyAuthenticationSuccessHandler(String url) {this.url = url;}@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {User user = (User) authentication.getPrincipal();System.out.println(user.getAuthorities());System.out.println(user.getUsername());System.out.println(user.getPassword());//密码被保护会输出nullresponse.sendRedirect(url);}
}

失败

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {private String url;public MyAuthenticationFailureHandler(String url) {this.url = url;}@Overridepublic void onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response,AuthenticationException exception) throws IOException, ServletException {response.sendRedirect(url);}
}

8.判断

权限判断

在自定义逻辑中创建的User中指定,严格区分大小写

return new User(username,password,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
.antMatchers("/main1.html").hasAnyAuthority("admin")

角色判断

return new User(username,password,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc"));
.antMatchers("/main1.html").hasAnyRole("abc")

ip判断

localhost和127.0.0.1的ip是不一样的需要指定特定的ip地址

9.基于注解开发

在启动类中添加注解@EnableGlobalMethodSecurity(securedEnabled = true)

@Secured

在controller层中添加

@Secured("ROLE_abc")
@RequestMapping("/toMain")
public String toMain(){return "redirect:main.html";
}

@PreAuthorize/@PostAuthorize

方法或类级别的注解

@PreAuthorize("hasRole('ROLE_abc')")

PreAuthorize表达式允许ROLE开头,也可以不用ROLE开头  

10.记住我功能

导入依赖

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>

自定义

在config中配置

@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private DataSource dataSource;
@Autowired
PersistentTokenRepository persistentTokenRepository;
http.rememberMe().tokenValiditySeconds(60)//自定义登录逻辑.userDetailsService(userDetailsService)//持久层对象.tokenRepository(persistentTokenRepository);//底层靠jdbc实现
@Bean
public PersistentTokenRepository getPersistentTokenRepository(){JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();jdbcTokenRepository.setDataSource(dataSource);//第一次启动时建表,第二次使用时注释掉//jdbcTokenRepository.setCreateTableOnStartup(true);return jdbcTokenRepository;
}

11.未完待续...

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

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

相关文章

navicat for oracle

前言 Oracle中的概念并不是创建数据库&#xff0c;而是创建一个表空间&#xff0c;然后再创建一个用户&#xff0c;设置该用户的默认表空间为我们新创建的表空间&#xff0c;这些操作之后&#xff0c;便和你之前用过的mysql数据库创建完数据库一模一样了。 创建数据库 使用O…

Error: Failed to download template from registry: fetch failed

第一次构建Nuxt项目时&#xff0c;出现在这样的错误&#xff01;&#xff01;&#xff01; 如果你也是这样得错误&#xff0c;修改hosts也没用。我试了 是因为你的npm安装了其他镜像源&#xff0c; 这个时候你就需要手动下载了&#xff1a; web端访问&#xff1a; https://ra…

Himawari-8 数据下载【利用FTP】

1 波段介绍 2 注册 数据下载之前&#xff0c;必须进行注册 JAXA Himawari Monitor | Registration 注册后&#xff0c;在邮箱里点击同意 邮箱会给出FTP的账号信息 3 下载FTP软件 点击进行新站点的新建 设置刚才邮箱里的主机、用户和密码 选择远程站点&#xff0c;选择自己…

权限系统模型:RBAC模型与ABAC模型

权限系统 基于角色的访问控制&#xff08;RBAC&#xff09; 基于角色的控制访问&#xff08;Role-Based Access Control&#xff0c;简称 RBAC&#xff09;&#xff0c;即&#xff1a;给予该账号角色&#xff08;Role&#xff09;&#xff0c;授权角色对应的相关权限&#xf…

STL篇一:string

文章目录 前言1. STL的简单理解1.1 什么是STL1.2 STL的版本1.3 STL的六大组件1.4 STL的重要性1.5 STL的缺陷 2. string类2.1 为什么学习string类&#xff1f;2.1.1 C语言中的字符串2.1.2 两个面试题 2.2 标准库中的string类2.2.1 string类(了解)2.2.2 string类的常用接口说明 2…

Kafka基本介绍

消息队列 产生背景 消息队列&#xff1a;指的数据在一个容器中&#xff0c;从容器中一端传递到另一端的过程 消息(message): 指的是数据&#xff0c;只不过这个数据存在一定流动状态 队列(queue): 指的容器&#xff0c;可以存储数据&#xff0c;只不过这个容器具备FIFO(先进…

kali_linux换源教程

vim /etc/apt/sources.list #阿里云deb http://mirrors.aliyun.com/kali kali-rolling main non-free contribdeb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib#清华大学源deb http://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib…

Android14实战:打破音频默认重采样的限制(五十二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

5文件操作

包含头文件<fstream> 操作文件三大类&#xff1a; ofstream : 写文件ifstream &#xff1a;读文件fstream : 读写文件 5.1文本文件 -文件以ascii的形式存储在计算机中 5.1.1写文件 步骤&#xff1a; 包含头文件 #include "fstream"创建流对象 ofs…

【STM32】STM32学习笔记-FlyMCU串口下载和STLINK Utility(30)

00. 目录 文章目录 00. 目录01. 串口简介02. 串口连接电路图03. FlyMCU软件下载程序04. 串口下载原理05. FlyMCU软件其它操作06. STLINK Utility软件07. 软件下载08. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式&#xff0c;因为它简…

WebRTC入门:基础的核心协议与概念(二十三)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

【C#】C#实现PDF合并

文章目录 一、下载iTextSharp.dll下载iTextSharp.dll命名空间引入 二、界面设计三、代码全局变量选择文件夹的按钮确认合并的按钮 四、导出结果五、完整源码 一、下载iTextSharp.dll 下载iTextSharp.dll 可使用联机方式或者文件下载方式。 命名空间引入 代码开始时引入了一…

Android Studio导入项目 下载gradle很慢或连接超时

AS最常见的问题之一就是下载gradle非常慢&#xff0c;还经常出现下载失败的情况&#xff0c;没有gradle就无法build项目&#xff0c;所以一定要先解决gradle的下载问题&#xff0c;下面教大家两种常用方法。 因为我的项目绝大多数使用的是gradle-5.6.4-all&#xff0c;下面就以…

【搜索引擎设计:信息搜索怎么避免大海捞针?

在前面我们提到了网页爬虫设计&#xff1a;如何下载千亿级网页&#xff1f;中&#xff0c;我们讨论了大型分布式网络爬虫的架构设计&#xff0c;但是网络爬虫只是从互联网获取信息&#xff0c;海量的互联网信息如何呈现给用户&#xff0c;还需要使用搜索引擎完成。因此&#xf…

MYSQL分表分库 详解

目录 一、垂直拆分于水平拆分的区别&#xff1f; 垂直拆分 水平拆分 二、分表分库有哪些策略&#xff1f; Hash分片策略 枚举分片策略 日期分片策略 范围分片策略&#xff08;用的较多&#xff09; 三、分表分库之后&#xff0c;如何查询的呢&#xff1f; 四、分表分…

【RHEL】Vivado调用VCS+Verdi联合仿真报错解决

问题描述 在使用VCS Verdi仿真Vivado工程时&#xff0c;点击行为仿真按钮进度条窗口消失后&#xff0c;Verdi窗口并未出现&#xff0c;查看消息报错如下&#xff1a; vcs: line 34205: 119837 Segmentation fault (core dumped) ${TOOL_HOME}/bin/cfs_ident_exec -f ${X…

网络安全已死,趁早转行?

近年来&#xff0c;曾经被寄予厚望的网络安全行业似乎正逐渐失去昔日的辉煌。曾经一度备受瞩目的网络安全专业&#xff0c;如今却面临着降薪、裁员的困境。许多公司对网络安全的重视程度不高&#xff0c;网络安全岗位成了背锅的代名词。在这样的环境下&#xff0c;有人开始质疑…

智能小车项目(七)通过PID实现给定和实际速度值计算PWM输出

我们先看大脑&#xff08;上位机nano&#xff09; keybord_ctrl节点发布’cmd_vel’消息消息类型为Twist队列大小为1 pub rospy.Publisher(cmd_vel, Twist, queue_size1)if not stop: pub.publish(twist)driver_node订阅这个消息 当有消息时cmd_vel_callback回掉函数处理消息…

感染嗜肺军团菌是什么感觉?

记录一下最近生病的一次经历吧&#xff0c;可能加我好友的朋友注意到了&#xff0c;前几天我发了个圈&#xff0c;有热心的朋友还专门私信了我说明了他自己的情况和治疗经验&#xff0c;感谢他们。 ​ 那么关于这次生病的经历&#xff0c;给大家分享一下。 首先&#xff0c;这次…

redis夯实之路-持久化之RDB与AOF详解

数据库 初始化服务器时会根据redisServer的dbnum属性来决定创建多少个数据库&#xff0c;默认为16 使用select切换数据库 客服端状态redisClient结构的db属性记录了当前的目标数据库 RedisDb结构的dict字典保存了数据库的所有键值对&#xff0c;这个字典被称为键空间。 cru…