1、什么是Spring Security?
springsecurity是一个功能强大且高度可定制的身份验证和访问控制框架。springsecurity是一个专注于为Java应用程序提供身份验证和授权的框架。与所有Spring项目一样,Spring安全性的真正威力在于它可以很容易地扩展以满足定制需求。
实际上,在Spring boot出现之前,Spring security已经发展了很多年,到那时由于强大的shiro,它一直不温不火。因为相对于Shiro,在SSH/SSM中整合Spring Security都是比较麻烦的操作,然而自从有了 Spring Boot 之后,Spring Boot 对于 Spring Security 提供了 自动化配置方案,可以零配置使用 Spring Security。
所以一般的推荐方案是:
- SSM + Shiro
- Spring boot/Spring Cloud + Spring Security
2、Spring Security 原理解析
Spring Security对Web资源的保护是靠Filter实现的。当初始化Spring Security时,会创建一个名为 springSecurityFilterChain 的Servlet过滤器,类型为org.springframework.security.web.FilterChainProxy,它实现了javax.servlet.Filter,因此外部的请求会经过此 类,下图是Spring Security过虑器链结构图:
这里FilterChainProxy是一个代理,真正起作用的是FilterChainProxy中SecurityFilterChain所包含的各个Filter,同时 这些Filter作为Bean被Spring管理,它们是Spring Security核心,各有各的职责,但他们并不直接处理用户的认 证,也不直接处理用户的授权,而是把它们交给了认证管理器(AuthenticationManager)和决策管理器 (AccessDecisionManager)进行处理。
所以spring Security功能的实现主要是由一系列过滤器链相互配合完成,如下图:
- SecurityContextPersistenceFilter :这个Filter是整个拦截过程的入口和出口(也就是第一个和最后一个拦截 器),会在请求开始时从配置好的 SecurityContextRepository 中获取 SecurityContext,然后把它设置给 SecurityContextHolder。在请求完成后将 SecurityContextHolder 持有的 SecurityContext 再保存到配置好的 SecurityContextRepository,同时清除 securityContextHolder 所持有的 SecurityContext。
- UsernamePasswordAuthenticationFilter :用于处理来自表单提交的认证。该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的 AuthenticationSuccessHandler 和 AuthenticationFailureHandler,这些都可以根据需求做相关改变。
- FilterSecurityInterceptor: 是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问
这里需要重点讨论的有两个概念,身份认证和授权。这也是Spring Security的主要职责。
身份认证
首先在usernamePasswordAuthenticationFilter中来拦截登录请求,并调用AuthenticationManager。
AuthenticationManager调用Provider
provider调用userDetaisService来根据username获取真实的数据库信息。
-
最终验证帐号密码的类是org.springframework.security.authentication.dao.DaoAuthenticationProvider
细节参考: Spring Security认证过程_Kevin-Zeng的博客-CSDN博客
授权
- Spring Security默认使用AffirmativeBased实现 AccessDecisionManager的decide 方法来实现授权
- 调用AccessDecisionVoter进行vote(投票)
- 只要有投通过(ACCESS_GRANTED)票,则直接判为通过。
- 如果没有投通过则 deny++ ,最后判断if(deny>0 抛出AccessDeniedException(未授权)
细节参考 : Spring Security授权过程_Kevin-Zeng的博客-CSDN博客
3、简单入手
数据库表结构
- 添加
用户表
,角色表
,用户角色关系表
- 插入数据
Spring + mybatis配置
- 添加pom
- 修改yml配置
- 主启动类
- 配置DBconfig.java (数据源)、MyBatisConfig.java (扫描mapper.xml文件)、MyBatisScannerConfig.java (dao 扫描器)、TransactionConfig.java (开启事物管理)
java bean
- 有三个bean ,sysuser(用户),sysrole(角色),msg(信息,用于和页面传递信息使用)
- dao 层实现(mapper.xml)
添加WebSecurityConfig
- 添加WebSecurityConfig.java 配置文件,用于管控登录访问权限
- 将url权限分配给角色
- 新建CustomUserService 用于将用户权限交给 springsecurity进行管控;需要实现 UserDetailsService接口
页面实现
- 添加login.html页面
- springMVC配置,注册访问/login 转向login.html 页面
4、OAuth2.0
OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。
它的大致流程是这样,
- 用户想操作存放在服务提供方的资源。
- 用户登录客户端向服务提供方请求一个临时令牌。
- 服务提供方验证客户端的身份后,授予一个临时令牌。
- 客户端获得临时令牌后,将用户引导至服务提供方的授权页面请求用户授权。在这个过程中将临时令牌和客户端的回调连接发送给服务提供方。
- 用户在服务提供方的网页上输入用户名和密码,然后授权该客户端访问所请求的资源。
- 授权成功后,服务提供方引导用户返回客户端的网页。
- 客户端根据临时令牌从服务提供方那里获取访问令牌。
- 服务提供方根据临时令牌和用户的授权情况授予客户端访问令牌。
-
客户端使用获取的访问令牌访问存放在服务提供方上的受保护的资源。
授权模式
授权码模式(authorization code)---- 授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
隐藏模式(implicit)---- 有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)"隐藏式"(implicit)。
密码模式(resource owner password credentials)---- 如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。
客户端模式(client credentials)---- 适用于没有前端的命令行应用,即在命令行下请求令牌。
更简单的理解可以参考 :
OAuth 2.0 的一个简单解释 - 阮一峰的网络日志 (ruanyifeng.com)
OAuth 2.0 的四种方式 - 阮一峰的网络日志 (ruanyifeng.com)