系列学习安全框架 Security 之第 1 篇 —— 认识 SpringSecurity
什么是 SpringSecurity?
Spring Security 是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
百度百科地址:https://baike.baidu.com/item/spring%20security/8831652?fr=aladdin
SpringCloud Security 是基于 Spring Security 为基础而开发的,因此我们学习了 SpringSecurity 就可以移植到 SpringCloud Security 了,详见中文社区网:https://www.springcloud.cc/
Security 应用场景
Security 在很多企业中作为后台角色权限框架、授权认证 Oauth2.0 、安全防护(防止跨站点请求)、Session攻击、非常容易融合SpringMVC使用等。
先下载本篇博客代码:https://pan.baidu.com/s/1R0Daoh7Zdw1-DQKrLYAbkw 提取码:pshm
本篇代码例子,主要是一个入门的 demo:有2个角色 admin 和 user,其中 admin 有增删改查权限,user 只有读的权限。通过整合 SpringSecurity 和 SpringBoot 来做权限控制,很多代码目前先写固定,主要是为了方便学习,后续会从数据库中读取。
SpringBoot 版本号:2.2.2.RELEASE,SpringCloud 版本号:Hoxton.SR2
首先,代码结构:
在 pom.xml 里,我们需要增加 security 的依赖和 freemarket 的依赖,主要做一些页面模板:
<!-- springboot整合freemarker --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!-->spring-boot 整合security --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
然后,templates 目录下的文件都比较简单,使用的是 freemarker 模板,需要提一点的就是 login 文件,用户名和密码是与 security 要求的字段名一致,然后在地址里判断是否有 error 而判断是登录失败,实际项目开发,不应该这样判断,目前是为了学习需要。
然后,WebServerAutoConfiguration 配置类,主要是为了自定义 WEB 服务器参数 可以配置默认错误页面。
package com.study.config;import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;/*** @author biandan* @description 自定义 WEB 服务器参数 可以配置默认错误页面* @signature 让天下没有难写的代码* @create 2021-05-30 下午 9:28*/
@Configuration
public class WebServerAutoConfiguration {@Beanpublic ConfigurableServletWebServerFactory webServerFactory() {TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400");ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401");ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN, "/error/403");ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");ErrorPage errorPage415 = new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "/error/415");ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");factory.addErrorPages(errorPage400, errorPage401, errorPage403, errorPage404, errorPage415, errorPage500);return factory;}
}
最后,需要讲解配置类:SecurityConfig
package com.study.config;import com.study.handler.MyAuthenticationFailureHandler;
import com.study.handler.MyAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @author biandan* @description* @signature 让天下没有难写的代码* @create 2021-05-30 下午 9:38*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate MyAuthenticationSuccessHandler successHandler;@Autowiredprivate MyAuthenticationFailureHandler failureHandler;// 配置认证用户信息和权限@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 添加admin账号,拥有增删改查权限auth.inMemoryAuthentication().withUser("admin").password("123").authorities("showUser","addUser","updateUser","deleteUser");// 添加user账号,只有查询权限auth.inMemoryAuthentication().withUser("user").password("456").authorities("showUser");}// 配置拦截请求资源@Overrideprotected void configure(HttpSecurity http) throws Exception {// 如何权限控制 给每一个请求路径 分配一个权限名称 然后账号只要关联该名称,就可以有访问权限http.authorizeRequests()// 配置查询用户权限.antMatchers("/showUser").hasAnyAuthority("showUser").antMatchers("/addUser").hasAnyAuthority("addUser").antMatchers("/updateUser").hasAnyAuthority("updateUser").antMatchers("/deleteUser").hasAnyAuthority("deleteUser").antMatchers("/login").permitAll().antMatchers("/**").fullyAuthenticated().and().formLogin().loginPage("/login").successHandler(successHandler).failureHandler(failureHandler).and().csrf().disable();}/* 不推荐使用这种方式,查看博客:https://blog.csdn.net/alinyua/article/details/80219500@Beanpublic static NoOpPasswordEncoder passwordEncoder() {return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();}*/@Beanpublic static PasswordEncoder passwordEncoder(){DelegatingPasswordEncoder encoder = (DelegatingPasswordEncoder)PasswordEncoderFactories.createDelegatingPasswordEncoder();encoder.setDefaultPasswordEncoderForMatches(NoOpPasswordEncoder.getInstance());return encoder;}}
需要注意的是我们需要增加 PasswordEncoder 的 Bean 注解,如果不增加会报错:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
原因是升级为 Security5.0 以上密码支持多种加密方式,我们需要恢复以前的模式,不推荐使用 NoOpPasswordEncoder 而是使用 PasswordEncoder。
我们还要禁用 csrf ,同时因为我们使用的是 FromLogin 的方式,如果不禁掉 csrf,必须在表单里传递 token 才能通过。我们设置登录不拦截,代码如下:
.antMatchers("/login").permitAll()
然后,我们需要增加认证成功处理类:
package com.study.handler;import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author biandan* @description 认证成功* @signature 让天下没有难写的代码* @create 2021-05-30 下午 9:43*/
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {String username = httpServletRequest.getParameter("username");System.out.println("认证成功,username="+username);//认证成功后跳转到主页httpServletResponse.sendRedirect("/");}
}
认证失败处理类:
package com.study.handler;import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author biandan* @description 认证失败* @signature 让天下没有难写的代码* @create 2021-05-30 下午 9:45*/
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {String username = httpServletRequest.getParameter("username");System.out.println("认证失败,username="+username);//重定向到登录页面,同时在地址后面增加 error 参数httpServletResponse.sendRedirect("/login?error");}
}
application.yml 配置:
server:port: 80# 将SpringBoot项目作为单实例部署调试时,不需要注册到注册中心
eureka:client:fetch-registry: falseregister-with-eureka: falsespring:application:name: security-server# 配置freemarkerfreemarker:# 设置模板后缀名suffix: .ftl# 设置文档类型content-type: text/html# 设置页面编码格式charset: UTF-8# 设置页面缓存cache: false# 设置ftl文件路径template-loader-path:- classpath:/templates# 设置静态文件路径,js,css等mvc:static-path-pattern: /static/**
OK,启动我们的微服务,浏览器地址输入:http://127.0.0.1/
输入 admin 账号,123密码,登录成功:
admin 有增删改查的权限,因此点击每个按钮都有权限。
然后我们切换到 user 账号,user 账号只有查询的权限,点击增删改提示权限不足。
同时我们查看后台日志:
OK,security 的核心流程我们讲解完毕,后面会讲解如何动态的分配权限。这篇博客仅仅做入门,实际开发不可能写固定用户名和密码、权限到代码里去的。
本篇博客代码:https://pan.baidu.com/s/1R0Daoh7Zdw1-DQKrLYAbkw 提取码:pshm
系列学习安全框架 Security 之第 1 篇 —— 认识 SpringSecurity相关推荐
- Hadoop学习笔记—15.HBase框架学习(基础知识篇)
Hadoop学习笔记-15.HBase框架学习(基础知识篇) HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase ...
- Vue框架里使用Swiper - 安装篇
Vue框架里使用Swiper npm安装swiper cnpm install swiper 相关阅读 Vue框架里使用Swiper 如何在Vue项目中优雅的使用swiper插件 https://ww ...
- Express框架的安装通信测试 - 讲解篇
文章目录 一. Express框架的安装: 通过cmd命令配置package.json ,cmd命令,依次如下: package.json 文件的代码更新后如下: index.js 代码如下: 简单的 ...
- ssm框架整合_框架整合战斗压缩粮篇SpringCloud+SpringBoot+SSM
各位小伙伴今天又敲了多少Bug了,今天改Bug又花了多长时间啦,我们每天就是敲Bug,敲完改,改完敲,习惯就好啦,心态摆正.Debug起来!!! 上次是Dubbo整合,今天终结篇Cloud整合,不要废 ...
- b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释
b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释 继续上篇,上篇里忘记了也很重要的前端部分,今天的网站基本上是以一个启示页,然后少量的整页切换,大量的浏览器后台调用web服务局部.动态更 ...
- SSM框架学习总结第零篇--框架是什么
SSM框架系列文章: SSM框架学习总结第零篇–框架是什么 SSM框架学习总结第一篇–MyBatis SSM框架学习总结第二篇–Spring SSM框架学习总结第三篇–Spring MVC SSM框架 ...
- 万字长文+图文并茂+全面解析微前端框架 qiankun 源码 - qiankun 篇
写在开头 微前端系列文章: 基于 qiankun 的微前端最佳实践(万字长文) - 从 0 到 1 篇 基于 qiankun 的微前端最佳实践(图文并茂) - 应用间通信篇 基于 qiankun 的微 ...
- hutol json null值没了_JSON数据处理框架Jackson精解第一篇-序列化与反序列化核心用法...
Jackson是Spring Boot默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的,没有这种限制.它提供了很 ...
- java移动端接口测试_走进Java接口测试之测试框架TestNG数据驱动(入门篇)
前言 我们在前面的文章中,和大家分享过接口自动化测试一些基本的实现方法,但是,你很快就会发现,如果在测试脚本中硬编码测试数据的话,测试脚本灵活性会非常低.而且,对于那些具有重复的请求,而只是测试入参不 ...
最新文章
- underscorejs之 _.indexBy(list, iteratee, [context])
- 少量数据训练语音识别的思路
- vs2012中使用localdb实例还原一个sql server 2008r2版本的数据库
- python 命令行参数-Python处理命令行参数
- 第一章:数组与指针概念剖析
- 3Sum探讨(Java)
- 《Effective C#》的读书笔记
- 杭州计算机学校哪家好,杭州2021年哪所计算机学校比较好
- Hadoop 新增删除节点
- 疲劳驾驶监测方案_【Nano Energy】TENG用于驾驶员驾驶状态监测
- java中biglong_Java的long和bigint长度对比详解
- stm32内部低速rtc_STM32时钟RCC详解
- 实用分享-Visual Studio图像查看插件(Image Watch)
- sublime text 显示 typescript高亮
- tp5 + 百度编辑器 +七牛云存储的实现办法
- 买哪个股票稳赚,三类股票,可以买了
- ShaderJoy —— “圆点消散” 的实现 【GLSL】
- uniapp父子组件传值
- `英语` 2022/8/18
- 【OpenCV】学习笔记(一):OpenCV4.5.5文件介绍