深入浅出SpringSecurity
SpringSecurity学习
SpringSecurity简介
安全框架的概述
什么是安全框架?是为了解决安全问题的框架。如果没有安全框架,我们需要手动处理每个资源的访问控制,非常麻烦。使用安全框架,我们可以通过的配置方式实现对资源的访问控制。
常用的安全框架概述
- SpringSecurity:Spring家族的一员,是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文配置的Bean,充分利用Spring IOC、DI(控制反转 Inversion of Control)、DI(依赖注入 Dependency Injection)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量的代码的重复工作。
- Apache Shiro:一个功能强大且易于使用的java安全框架,提供了认证和授权、加密、和会话管理。
概述
Spring Security是一个高度自定义的安全框架。利用 Spring 1oC/Dl和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。
使用Spring Secruity 的原因有很多,但大部分都是发现了javaEE的 Servlet 规范或 EJB规范中的安全功能缺乏典型企业应用场景。同时认识到他们在 WAR 或 EAR 级别无法移植。因此如果你更换服务品环境,还有大量工作去重新配置你的应用程序。使用 Spring Security解决了这些问题,也为你提供许多其他有用的、可定制的安全功能。
正如你可能知道的两个应用程序的两个主要区域是认证"和"授权”(或者访问控制)。
这两点也是 Spring Security 重要核心功能。
“认证”,是建立一个他声明的主体的过程(一个“主体”—般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统),通俗点说就是系统认为用户是否能登录。
“授权"指确定—个主体是否允许在你的应用程序执行一个动作的过程。通俗点讲就是系统判断用户是否有权限去做某些事情。
源码分析
UserDetailsService
UserDetails
User
可以看到这个user类,这个user类,可不是我们平时定义的user类。这是SpringSecurity中定义的user类。
它最主要的有两个构造函数。
它这个password是我们根据userdetailsService的loadUserByUsername(username) 去数据库中查出来的数据。
是不是很像我们平时开发的逻辑。
具体使用
自定义登录逻辑
在我们使用SpringSecurity做开发的时候,我们其实只有去实现两个接口。
一个是UserDetailsService、另一个就是PasswordEncoder。
自定义username
前面的根据是调用 loadUserByUsername(username) 去数据库查询用户,而要实现登陆的工能,就需要我们来自定义实现,所以就要用到PasswordEncoder接口。用来对用户数的密码加密,同时在和数据库中加过密的密码,来进行匹配。只要匹配成功,就可以实现登陆逻辑。
其实呢我们倒入依赖的时候,它就要实现。在我们的demo中,程序的启动之后控制台会打印一句话。
他的意思就是,自动生成的密码,在demo中我们自定义了,login 方法。
当我们在浏览器中使用login 方法,来实现登录的时候我们会发现。莫名其妙的弹出来一个login界面。我还以为是我自己写的。一想我咋可能写出这么好看的登录界面。确定的是,这肯定不是我自己写的。
所以呢,这就是SpringSecurity中自带的登录页面,目的就是为了,对用户进行拦截和认证。只要登录的用户才会被授权,进行后续的操作。
它规定的username,就是user,密码就是控制台打印的。
那倒我们要拿着玩意实现我们的登录逻辑嘛,显然是不可能。所以我们要再次基础上自定义我们的登录逻辑。
首先,我们肯定要重写 UserDetailsService 的 loadUserByUsername(username)的方法,为什么呢?
显然不同的用户有不同的username,所赋予的权限也不同。肯定需要重写。
接下来,我们平时的登录业务,大体上都是根据username,去数据库查询,查询到了返回整个对象实体,然后在根据前端用户输入的密码,和数据库查询带过来的对象实体中的密码,进行匹配。
可是,我们也看到,它这个密码显然是加过密了,所以呢,我们也需要对前端传过来的密码,也要进行一个加密,在和数据库中的密码进行匹配。当然了,在真实的开发,数据库当然是不会存明文密码,你懂的。
自定义登录密码
所以呢,我也需要实现这个PasswordEncoder接口。对我们用户输入的密码,进行加密。然后在登录的业务中,进行匹配。
那接下来,我们就看看这个接口。
常用的也就是,加密和匹配。它这个加密是不可逆的。
那我们简单的把玩一下这个 BCryptPasswordEncoder
@SpringBootTest
public class PasswordEncoder_test {@Testpublic void test(){BCryptPasswordEncoder bc = new BCryptPasswordEncoder();//对原始的密码进行加密String encode = bc.encode("123");System.out.println(encode);//原始密码和加过密的进行匹配boolean matches = bc.matches("123", encode);System.out.println(matches);}
}//测试结果
$2a$10$cl18e/WgokCZsHpvdJWHbO7QOcDxZUWMVn5JtSAdIObpZ08JUs8XW
true
但是在我们的平常使用中springSecurity要求我们在spring的容器中有一个实例,所以我们平时都会一个配置类。配合@Configuration注解。@Bean注解。
在这里,我们拓展一下。使用SpringBoot做开发的同学。对下面的这个配置类,不少见吧。可是你真的知道这两个注解的作用吗?
@Configuration注解,就像当于我们在用Spring开发写的xml配置文件的作用。而@Bean就相当于我们在xml中写的标签。@Bean注解作用在方法上,声明当前方法的返回值是一个Bean。
package com.uin.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @author wanglufei* @description: SpringSecurity配置类* @date 2022/4/10/7:51 PM*/
@Configuration
public class SpringSecurityConfig{/*** BCryptPasswordEncoder实例** @return org.springframework.security.crypto.password.PasswordEncoder* @author wanglufei* @date 2022/4/11 8:32 AM*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
自定义登录。
package com.uin.service.impl;import org.springframework.beans.factory.annotation.Autowired;
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;/*** @author wanglufei* @description: 实现SpringSecurity中的UserDetailsService* @date 2022/4/11/8:43 AM*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@AutowiredPasswordEncoder passwordEncoder;/*** 自定义username** @param username* @return org.springframework.security.core.userdetails.UserDetails* @author wanglufei* @date 2022/4/11 8:44 AM*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//1.根据username去查询数据库,不存在的就会抛出异常UsernameNotFoundExceptionif (!"admin".equals(username)) {return (UserDetails) new UsernameNotFoundException("用户名不存在");}//2.把查询的密码(注册是已经加过密)进行解析,或者直接把密码放入构造方法String password = passwordEncoder.encode("123");return new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));}
}
我们会发现控制台并没有,打印刚才自动生成的密码,
发现是可以登录的。
当然自定义登录逻辑,远远不止于此。
自定义登录页面
我们不可能,一直用它这个登录页面吧,所以我们需要自定义登录页面。在SpringSecurity中有一个这样的类,提供我们做一些自定义的配置。
记得把super.configure(http)。这个是默认的配置。
页面太丑,反正实现效果了。
但是我们会发现一个问题,我们不登陆也可以访问main.html。这不就bbq了。所以我们要拦截请求。
但是在SpringSecurity里,它就做授权,授于你权利,让你去那个页面,就很像我们的在SSM中配置的拦截器。所以我们要转换一下概念,入乡随俗嘛。
这个就起到了,拦截器的作用。
哇涩,重定向次数过多。想了一下,好像我们去访问login.html页面也被拦截了,有点想一个死递归,死循环。
自定义登录失败跳转页面
自定义登录参数
工作流程
spring security 入门教程 详细讲解 - Caesar_the_great - 博客园 (cnblogs.com)
认证流程(authentication)
授权流程(authorization)
优点
- 将用户登录,权限控制分离出来,达到和其他控制、逻辑代码完全分离。
- 在控制、逻辑代码里面,可以通过spring容器的到我们登录用户的信息,可插拔性的体现。
- 自定义的权限控制访问,不但是对某个URL可操控,同时可以对某个方法进行控制。
- 提供一些登录相关的操作,如记住我、登录成功跳转页面设定等等。
- 安全控制性好,对并发session可控性好。
实现匿名访问
spring security 实现匿名访问 - Caesar_the_great - 博客园 (cnblogs.com)
思路
- 标注需要匿名访问的接口
- 配置匿名访问
实例
自定义注解 @AnonymousAccess,写在需要匿名访问的接口上:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {
}
/*** 功能描述: 登录* @param loginVO 用户登录时的账号和密码* @Description TODO* @return com.rman.iflash.model.R* @Author Caesar* @Date 10:57 2020/5/3**/@AnonymousAccess@PostMapping("/login")public R login(@RequestBody @Validated LoginVO loginVO){log.info("用户登录信息{}", loginVO);LoginVO authUserDTO = new LoginVO();authUserDTO.setUsername(loginVO.getUsername());authUserDTO.setPassword(loginVO.getPassword());authUserDTO.setCaptchaId(loginVO.getCaptchaId());authUserDTO.setCaptchaCode(loginVO.getCaptchaCode());Object data = loginService.login(authUserDTO);return R.success(data);}
在security的配置类的 configure(HttpSecurity http)方法中配置匿名访问:
//查找匿名标记URLMap<RequestMappingInfo, HandlerMethod> handlerMethods =applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();Set<String> anonymousUrls = new HashSet<>();for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethods.entrySet()) {HandlerMethod handlerMethod = infoEntry.getValue();AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);if (anonymousAccess != null) {anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());}}anonymousUrls.forEach(s -> log.warn("可以匿名访问的url:{}", s));http.antMatchers(anonymousUrls.toArray(new String[0])).anonymous()
深入浅出SpringSecurity相关推荐
- 我的爬虫都爬出了些什么?
电机学第七版乌曼课后答案 电化学方法原理和应用第二版邵元华课后答案 电力系统继电保护黄少锋课后答案 生物化学第4版同步辅导与习题集朱圣庚PDF 机床数控技术及应用第四版陈蔚芳课后答案 机器视觉算法与应 ...
- 我写了一套SpringBoot+SpringSecurity+Vue权限系统 实战课程,免费分享给CSDN的朋友们
大家好,我是锋哥,最近写了一套前后端分离的权限系统,逼格略高,专门为Java初学者提升技术层次和方便就业而精心打造.希望你们喜欢!(文末领取) 一,Java就业实战课程简介: 本课程采用主流的技术栈实 ...
- SpringSecurity安全验证中文乱码问题
使用SpringSecurity做安全验证时发现form表单中提交中文名会出现乱码问题. 原因是因为我在web.xml配置文件中将springSecurityFilterChain拦截器放在了 cha ...
- Python --深入浅出Apriori关联分析算法(二) Apriori关联规则实战
上一篇我们讲了关联分析的几个概念,支持度,置信度,提升度.以及如何利用Apriori算法高效地根据物品的支持度找出所有物品的频繁项集. Python --深入浅出Apriori关联分析算法(一) 这次 ...
- MSDN Webcast“深入浅出ASP.NET AJAX系列”
课程: ASP.NET AJAX深入浅出系列课程(1):ASP.NET AJAX 概述(3月13日):对于ASP.NET AJAX的大致功能进行概述和演示,通过简单的演示让听众了解到ASP.NET A ...
- 5.3Role和Claims授权「深入浅出ASP.NET Core系列」
5.3Role和Claims授权「深入浅出ASP.NET Core系列」 原文:5.3Role和Claims授权「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁. ...
- Spring源码分析【8】-分布式环境SpringSecurity保持用户会话
1.SpringSecurity的权限控制流程是这样的: 用户登录,基础信息UserInfo存在SpringSecurity的ThreadLocal里. 下面是contextHolder对象: fin ...
- SpringSecurity学习:1(第一个SpringSecurity项目)
此博客是记录自己学习过程的记录 第一个SpringSecurity项目 导入依赖 详细的步骤我就不多说了,使用IDEA创建过SpringBoot项目的人一般都能看懂. 这一步我们可以在使用IDEA创建 ...
- Java项目:在线淘房系统(租房、购房)(java+SpringBoot+Redis+MySQL+Vue+SpringSecurity+JWT+ElasticSearch+WebSocket)
源码获取:博客首页 "资源" 里下载! 该系统有三个角色,分别是:普通用户.房屋中介.管理员.普通用户的功能:浏览房屋信息.预约看房.和中介聊天.申请成为中介等等.房屋中介的功能: ...
- SpringSecurity使用 配置文件 和wen.xml 文件配置
目录 1.web.xml 文件配置 2.spring-security 普通 为使用自己创建的认证类 1.web.xml 文件配置 !-- 配置SpringSecurity的拦截器 -->&l ...
最新文章
- 我的华为P30pro手机升级了鸿蒙系统!
- js java socket_js使用WebSocket,java使用WebSocket
- mixin network_基于Mixin Network的Go语言比特币开发教程 : 用 Mixin Messenger 机器人接受和发送比特币...
- mysql过滤器_MYSQL复制过滤器
- TCC分布式实现原理及分布式应用如何保证高可用
- (23)css3文字阴影text-shadow
- oracle date 隐式转换,PL/SQL中的数据类型隐式转换规则
- oracle游标fetch_SQL游标@@ FETCH_STATUS函数概述
- 125条常见的java面试笔试题大汇总2
- 机器学习算法-10贝叶斯信念网络、聚类算法、基于密度的方法DBSCAN
- Spring整合log4j日志组件(转)
- UDS协议入门之10服务
- 数字电路:数据选择器与译码器
- 画出属于你的最漂亮的数字时序图—WaveDrom
- 【QT小记】设置窗口背景透明
- 笔记本加固态小白怎么设置
- PL/0 语言简介、PL/0 文法
- matlab与maple互联,Maple与Matlab
- [Chaosblade] chaosblade-jvm-exec和chaosblade交互
- 物联网打破传统行业的枷锁,加速传统行业智能化!