SpringSecurity权限管理基本概念和整体架构介绍
文章目录
一、权限管理
基本上涉及到⽤户参与的系统都要进⾏权限管理,权限管理属于系统安全的范畴,权限管理实现对⽤户访问系统的控制,按照安全规则或者安全策略控制⽤户可以访问⽽且只能访问⾃⼰被授权的资源。
权限管理包括⽤户身份认证和授权两部分,简称认证授权。对于需要访问控制的资源⽤户⾸先经过身份认证,认证通过后⽤户具有该资源的访问权限⽅可访问。
也就是通过身份认证检查是否有进入系统的权利,通过授权检查是否有访问特定资源的权利。
1、认证
身份认证,就是判断⼀个⽤户是否为合法⽤户的处理过程。最常⽤的简单身份认证⽅式是系统通过核对⽤户输⼊的⽤户名和⼝令,看其是否与系统中存储的该⽤户的⽤户名和⼝令⼀致,来判断⽤户身份是否正确。对于采⽤指纹等系统,则出示指纹;对于硬件Key
等刷卡系统,则需要刷卡
2、授权
授权,即访问控制,控制谁能访问哪些资源。主体进⾏身份认证后需要分配权限⽅可访问系统的资源,对于某些资源没有权限是⽆法访问的
3、对权限控制,现有的解决方案
和其他领域不同,在 Java
企业级开发中,安全管理框架⾮常少,⽬前⽐较常⻅的就是:
-
Shiro
Shiro
本身是⼀个⽼牌的安全管理框架,有着众多的优点,例如轻量、简单、易于集成、可以在JavaSE
环境中使⽤等。不过,在微服务时代,Shiro
就显得⼒不从⼼了,在微服务⾯前和扩展⽅⾯,⽆法充分展示⾃⼰的优势 - 开发者⾃定义
也有很多公司选择⾃定义权限,即⾃⼰开发权限管理。但是⼀个系统的安全,不仅仅是登录和权限控制这么简单,我们还要考虑种各样可能存在的⽹络政击以及防彻策略,从这个⻆度来说,开发者⽩⼰实现安全管理也并⾮是⼀件容易的事情,只有⼤公司才有⾜够的⼈⼒物⼒去⽀持这件事情。 -
Spring Security
Spring Security
,作为Spring
家族的⼀员,在和Spring
家族的其他成员如
Spring Boot
、Spring Clond
等进⾏整合时,具有其他框架⽆可⽐拟的优势,同
时对OAuth2
有着良好的⽀持,再加上Spring Cloud
对Spring Security
的
不断加持(如推出Spring Cloud Security
),让Spring Securiy
不知不
觉中成为微服务项⽬的⾸选安全管理⽅案。
二、SpringSecurity简介
1、官方定义
查看官方介绍:https://spring.io/projects/spring-security
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements.
Spring Security是⼀个功能强⼤、可⾼度定制的身份验证和访问控制框架。它是保护基
于Spring的应⽤程序的事实标准。
Spring Security是⼀个⾯向Java应⽤程序提供身份验证和安全性的框架。与所有Spring
项⽬⼀样,Spring Security的真正威⼒在于它可以轻松地扩展以满⾜定制需求。
总结:Spring Security
是⼀个功能强⼤、可⾼度定制的身份验证和访问控制的框架。或者说⽤来实现系统中权限管理的框架。
2、历史
Spring Security
最早叫 Acegi Security
, 这个名称并不是说它和 Spring
就没有关系,它依然是为Spring
框架提供安全⽀持的。Acegi Security
基于 Spring
,可以帮助我们为项⽬建⽴丰富的⻆⾊与权限管理系统。Acegi security
虽然好⽤,但是最为⼈诟病的则是它臃肿烦琐的配置这⼀问题最终也遗传给了 Spring Security
。
Acegi Security
最终被并⼊ Spring Security
项⽬中,并于 2008 年4⽉发布了改名后的第⼀个版本 Spring Security 2.0.0
。和 Shiro
相⽐,Spring Security
重量级并且配置烦琐,直⾄今天,依然有⼈以此为理由⽽拒绝了解 Spring Security
。其实,⾃从 Spring Boot
推出后,就彻底颠覆了传统了 JavaEE
开发,⾃动化配置让许多事情变得⾮常容易,包括Spring Security
的配置。在⼀个Spring Boot
项⽬中,我们甚⾄只需要引⼊⼀个依赖,不需要任何额外配置,项⽬的所有接⼝就会被⾃动保护起来了。在 Spring Cloud
中,很多涉及安全管理的问题,也是⼀个Spring Security
依赖两⾏配置就能搞定,在和
Spring
家族的产品⼀起使⽤时,Spring Security
的优势就⾮常明显了。
因此,在微服务时代,我们不需要纠结要不要学习 Spring Security
,我们要考虑的是如何快速掌握Spring Security, 并且能够使⽤ Spring Security
实现我们微服务的安全管理。
三、整体架构
应用程序安全性可以归结为差不多两个独立的问题:身份验证(你是谁?)
和授权(你可以做什么?)
。有时候,人们会说“访问控制”而不是“授权”,“授权”会让人感到困惑,可以这样想:“授权”在其他地方已经被使用,为了避免歧义而用“访问控制”来描述。 Spring Security
有一个旨在将认证与授权分开的体系结构,并兼备多种策略和扩展点。
在Spring Security
架构设计中,认证和授权 是分开的,⽆论使⽤什么样的认证⽅式。都不会影响授权,这是两个独⽴的存在,这种独⽴带来的好处之⼀,就是可以⾮常⽅便地整合⼀些外部的解决⽅案。
1、认证
AuthenticationManager
在Spring Security
中认证是由AuthenticationManager
接⼝来负责的,接⼝定义为
它只有一个核心方法Authentication authenticate(Authentication authentication)
一个 AuthenticationManager
认证管理者可能会在 authenticate()
方法中做下面三件事中的任意一个:
- 如果认证成功,返回
Authentication
(通常它的authenticated
属性为true
authenticated=true
) . - 如果认证失败,抛出
AuthenticationException
异常. - 如果无法判断,返回
null
对于AuthenticationException
是一个运行时异常。通常由应用程序以通用方式处理,具体取决于应用程序的风格或目的。 换句话说,用户代码通常不会捕获和处理。需要用户自己去处理这个异常。
AuthenticationManager
最常用的实现是 ProviderManager
,在ProviderManager
中管理了众多 AuthenticationProvider
实例。在⼀次完整的认证流程中,Spring Security
允许存在多个 AuthenticationProvider
,⽤来实现多种认证⽅式,这些
AuthenticationProvider
都是由ProviderManager
进⾏统⼀管理的。
具体的代码实现:
Authentication
在Spring Security
中,通过Authentication
来封装用户的验证请求信息,Authentication
可以是需要验证和已验证的用户请求信息封装。认证以及认证成功的信息主要是由 Authentication
的实现类进⾏保存的,其接⼝定义
为
这个类非常的重要。对于
UsernamePasswordAuthenticationToken
或者是RememberMeAuthenticationToken
都是基于这个的。
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated) throws
IllegalArgumentException; }
-
getAuthorities
获取⽤户权限信息 -
getCredentials
获取⽤户凭证信息,⼀般指密码 -
getDetails
获取⽤户详细信息 -
getPrincipal
获取⽤户身份信息,⽤户名、⽤户对象等
-isAuthenticated
⽤户是否认证成功
SecurityContextHolder
SecurityContextHolder
是用来存储认证信息的,以方便保存用户的状态,供线程内所有方法使用SecurityContext
,也就是用户信息。
SecurityContextHolder
⽤来获取登录之后⽤户信息。Spring Security
会将登录⽤户数据保存在 Session
中。但是,为了使⽤⽅便,Spring Security
在此基础上还做了⼀些改进,其中最主要的⼀个变化就是线程绑定。当⽤户登录成功后,Spring Security
会将登录成功的⽤户信息保存到 SecurityContextHolder
。SecurityContextHolder
中的数据保存默认是通过ThreadLocal
来实现的,使⽤ThreadLocal
创建的变量只能被当前线程访问,不能被其他线程访问和修改,也就是⽤户数据和请求线程绑定在⼀起。当登录请求处理完毕后,Spring Security
会将SecurityContextHolder
中的数据拿出来保存到 Session
中,同时将SecurityContexHolder
中的数据清空。以后每当有请求到来时,Spring Security
就会先从 Session
中取出⽤户登录数据,保存SecurityContextHolder
中,⽅便在该请求的后续处理过程中使⽤,同时在请求结束时将 SecurityContextHolder
中的数据拿出来保存到 Session
中,然后将 Security SecurityContextHolder
中的数据清空。这⼀策略⾮常⽅便⽤户在Controller、Service
层以及任何代码中获取当前登录⽤户数据。
2、授权
当完成认证后,接下来就是授权了。在 Spring Security
的授权体系中,有两个关键接⼝
AccessDecisionManager
AccessDecisionManager
(访问决策管理器),⽤来决定此次访问是否被允许
注意这里的ConfigAttribute
类,后文会提到。
AccessDecisionVoter
AccessDecisionVoter
(访问决定投票器),投票器会检查⽤户是否具备应有的⻆⾊,进⽽投出赞成、反对或者弃权票。
AccesDecisionVoter
和 AccessDecisionManager
都有众多的实现类,在
AccessDecisionManager
中会换个遍历 AccessDecisionVoter
,进⽽决定是否允许⽤户访问,因⽽ AaccesDecisionVoter
和 AccessDecisionManager
两者的关系类似于 AuthenticationProvider
和 ProviderManager
的关系。
ConfigAttribute
ConfigAttribute
,⽤来保存授权时的⻆⾊信息
上文中有提到ConfigAttribute
, 在 Spring Security
中,⽤户请求⼀个资源(通常是⼀个接⼝或者⼀个 Java
⽅法)需要的⻆⾊会被封装成⼀个ConfigAttribute
对象,在 ConfigAttribute
中只有⼀个getAttribute
⽅法,该⽅法返回⼀个 String 字符串,就是⻆⾊的名称。⼀般来说,⻆⾊名称都带有⼀个 ROLE_
前缀,投票器 AccessDecisionVoter
所做的事情,其实就是⽐较⽤户所具各的⻆⾊和请求某个资源所需的ConfigAtuibute
之间的关系。
三者的关系可以用这张图来表示。对于ConfigAttribute
是一个对比器,用来对比用户权限的。