一、简介
https://docs.spring.io/spring-security/site/docs/4.2.10.RELEASE/guides/html5/helloworld-xml.html
SpringSecurity 融合 Spring 技术栈,提供 JavaEE 应 用的整体安全解决方案;
Spring Security 为基于 Java EE 的企业软件应用提供全面的安全服务。
Spring Security 只需要少量配置,就能构建一个强大的安全的应用系统。
目前市面上受欢迎的两个安全框架:Apache Shiro、SpringSecurity;
SpringSecurity 可以无缝整合 Spring 应用,具有强大的自动化 web 安全管控功能。而 Shiro 是一个轻量级强大的安全框架,可以脱离 web 应用来提供安全管控,但是对于 web 的一些定制安全需要手动编写;SpringBoot 底层默认整合 SpringSecurity 作为安全框架,所以我们推荐 web 应用使用 SpringSecurity 来控制安全;
1、文档
Hello Spring Security <https://github.com/spring-projects/spring-security/tree/4.2.10.RELEASE/samples/javaconfig/helloworld > 基于 Java 配置整合示例
Hello Spring Security Boot https://github.com/spring-projects/spring-security/tree/4.2.10.RELEASE/samples/boot/helloworld 与 SpringBoot 整合案例
Hello Spring Security XML https://github.com/spring-projects/spring-security/tree/4.2.10.RELEASE/samples/xml/helloworld 基于 XML 方式整合示例
Hello Spring MVC Security https://github.com/spring-projects/spring-security/tree/4.2.10.RELEASE/samples/javaconfig/hellomvc SpringMVC 集成示例
Custom Login Form https://github.com/spring-projects/spring-security/tree/4.2.10.RELEASE/samples/javaconfig/form 自定义登录表单示例
2、使用方式
一种是全部利用配置文件,将用户、权限、资源(url)硬编码在 xml 文件中
二种是用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置
三种是细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器, 并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。四是修改 springsecurity 的源代码,主要是修改 InvocationSecurityMetadataSourceService 和 UserDetailsService 两个类。
InvocationSecurityMetadataSourceService
将配置文件或数据库中存储的资源(url)提取出来加工成为 url 和权限列表的 Map 供 Security 使用
UserDetailsService
 提取用户名和权限组成一个完整的(UserDetails)User 对象,该对象可以提供用户的详细信息供 AuthentationManager 进行认证与授权使用
3、概念
认证
 authenfication: 身份验证
 “身份验证” 是指建立主体(principal)的过程,主体就是他们声称的是谁 (“主体” 通常指用户、设备或在应用程序中可以执行动作的其他系统)。也就是 “证明你是谁”。
授权
 authorization: 授权
 “授权” 是指确定主体(principal) 是否被允许执行系统中某个动作的过程。也就是 “你能做什么!”
为了达到“授权”决策(安全框架决定你是否有权限做此事),“身份验证”(authentication)过程已经建立了主体的身份(Principal)
二、SpringSecurity-HellWorld
1、测试环境搭建
1.1 创建普通的 maven-war 工程:spring-security-helloworld
 注意:以下所有的测试都采用的 Idea 集成开发工具
pom 文件增加依赖
1  | <dependencies>  | 
web.xml 配置
1  | 
  | 
spring 配置:spring.xml
1  | 
  | 
导入实验资源
- 需要资源的博客末尾有下载地址
 - 导入页面
 

- 导入 controller
 

运行测试

2、引入 SpringSecurity 框架
2.1 添加 security-pom 依赖
1  | <dependency>  | 
2.2 web.xml 中添加 SpringSecurity 的 Filter 进行安全控制
1  | <filter>  | 
2.3 加入 SpringSecurity 配置类
- @Configuration、@Bean 注解作用
 
1  | //声明当前类是一个配置类。相当与XML配置文件作用。  | 
2.4 启动测试效果

- 所有资源访问受限(包括静态资源)
 - 框架自带一个默认的登录界面
 - 账号密码错误会有提示
 

- 查看登录页面的源码,发现有个 hidden-input: name = “
_csrf“ 这个是 springsecurity 帮我们防止“跨站请求伪造”攻击;还可以防止表单重复提交。 

三、SpringSecurity 实验
1、实验一: 授权首页和静态资源
- 配置类 (AppWebSecurityConfig extends WebSecurityConfigurerAdapter)
 - 重写 configure(HttpSecurity http)方法
 
1  | // 声明当前类是一个配置类。相当于XML配置文件作用。  | 
- 测试结果
 
静态资源和 index.jsp 都可以访问

不存在的资源
- 有权限无资源 400
 

- 无权限
 

2、实验二: 默认及自定义登录页
1  | 
  | 

1  | 
  | 
 在访问没有权限资源或页面时,将会自动跳转到index.jsp登录页面
- 在测试的时候需要先暂时
_csrf这个功能 
1  | http.csrf().disable();  | 
3、实验三: 自定义表单登录逻辑分析
1  | 
  | 
表单提交地址:${PATH }/index.jsp
表单提交请求方式:post
提交表单:
- 引入 jquery: <script src=”${PATH }/layui/jquery.min.js”></script>
 - $(“form”).submit();
 


如果没有关闭 CSRF, 提交请求被拒绝, 需要暂时禁用 csrf:http.csrf().disable();

- 表单提交请求失败,提取错误消息:**${SPRING_SECURITY_LAST_EXCEPTION.message}**
 
1  | <div class="layadmin-user-login-box layadmin-user-login-header">  | 

4、实验四: 自定义认证用户信息
1  | 
  | 
 输入用户名和密码之后一致,就可以登录页面后台,前提是与自己基于内存认证方式一致的用户名和密码

- CSRF 跨站请求伪造
 - SpringSecurity 添加了 crsf 功能 【DefaultCsrfToken】,所有的表单提交为了防止跨站请求的伪造,我们需要加上_csrf 项;或者,暂时禁用 
http.csrf().disable(); 
1  | // 可以在页面任意位置加,没有唯一性  | 

5、实验五:用户注销完成
1  | 
  | 
1  | <li class="layui-nav-item">  | 

/logout: 退出系统
如果csrf 开启,必须post、方式的/logout 请求,表单中需要增加 csrf tokenlogoutUrl();退出系统需要发送的请求
logoutSuccessUrl();退出系统成功以后要跳转的页面地址
addLogoutHandler():自定义注销处理器
deleteCookies():指定需要删除的 cookie
invalidateHttpSession():session 失效(DEBUG)
6、实验六:基于角色的访问控制
1  | 
  | 
注意:
1.  将.anyRequest().authenticated()错误的设置在前面,后面的设置就不起作用了。
- 设置所有, “/**“ 都可以访问,其他再进行的设置就不会起作用了
 - 设置匿名访问/level3/** 可以不用登录,匿名访问:
.anyRequest().anonymous(); 
拥有该角色的资源可以访问,否则不可以访问
1  | 
  | 
7、实验七:自定义访问拒绝处理页面
直接增加处理映射界面
1  | http.exceptionHandling().accessDeniedPage("/unauth.html");  | 
在控制器类中增加映射处理
1  | 
  | 
增加显示页面,将 main.jsp 复制,命名为 unauth.jsp,增加一句提示信息
1  | <h1>你无权访问该页面...</h1>  | 

测试显示效果

8、实验八:记住我功能
8.1 记住我功能-免登录原理
1  | http.rememberMe();  | 
默认规则
- 页面 checkbox 提交 
remember-me参数 

- 默认记住 2 周登录状态:
AbstractRememberMeServices 

- 会在cookie中保存名为:remember-me 的 cookie
 

- 登录后页面,关闭浏览器,直接访问:http://localhost:8080/SpringSecurity/main.html 可以成功访问,不必登录。
 - 这种方式,token 值是放置在内存中的,服务器端重启 tomcat,token 会失效。需要将 token 记录在数据库持久化才不会失效。
 
8.2 记住我-数据版
引入 pom.xml 包
1  | <dependency>  | 
配置数据源
1  | <!-- 配置数据源 -->  | 
创建表
1  | create table persistent_logins (  | 


设置记住我
1  | 
  | 


四、认证
1、自定义 UserDatailsService 检索用户
创建表结构
1  | CREATE TABLE `t_admin` (  | 
配置 configure(AuthenticationManagerBuilder auth)
1  | 
  | 
编写 UserDetailService 实现

1  | 
  | 
运行测试结果,密码不一致,跳转到登录页,并提示错误消息

2、基于数据库(MD5 密码)认证
2.1 配置 configure(AuthenticationManagerBuilder auth)
1  | 
  | 
2.2 引入 MD5 加密工具类:MD5Util.java
1  | package com.oy.security.component;  | 
2.3 PasswordEncoder 接口实现类:PasswordEncoderImpl
1  | 
  | 
3、基于数据库(BCryptPasswordEncoder)密码加密认证
3.1 PasswordEncoder 接口

3.2 使用 BCryptPasswordEncoder 进行密码加密
1  | /**  | 
3.3 本地测试
1  | public class BCryptPasswordEncoderTest {  | 
3.4 服务器运行测试
将生成的密文存储到数据库中(注意:userpswd字段长度)把 userpaswd 字段长度扩大,重新启动服务器进行测试。










