Spring Security OAuth2.0认证授权知识概括 您所在的位置:网站首页 oauth2认证流程图 Spring Security OAuth2.0认证授权知识概括

Spring Security OAuth2.0认证授权知识概括

2023-05-15 03:32| 来源: 网络整理| 查看: 265

@[TOC](Spring Security OAuth2.0认证授权知识概括)

安全框架基本概念

什么是认证:

进入移动互联网时代,大家每天都在刷手机,常用的软件有微信、支付宝、头条等,下边拿微信来举例子说明认证相关的基本概念,在初次使用微信前需要注册成为微信用户,然后输入账号和密码即可登录微信,输入账号和密码 登录微信的过程就是认证。 系统为什么要认证? ①认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源。 认证 : ①用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。 ②常见的用户身份认证方式有:用户名密码登录,二维码登录,手机短信登录,指纹认证等方式。

什么是会话:

用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保证在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制,常见的有基于session方式、基于token方式等。 基于session的认证方式如下图: ①它的交互流程是,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话)中,发给客户端的sesssion_id 存放到 cookie 中。 ②这样用户客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户的合法校验,当用户退出系统或session过期销毁时,客户端的session_id也就无效了。 在这里插入图片描述 基于token方式如下图: ①它的交互流程是,用户认证成功后,服务端生成一个token发给客户端,客户端可以放到 cookie 或 localStorage等存储中,每次请求时带上 token,服务端收到token通过验证后即可确认用户身份。 在这里插入图片描述 总结: ①基于session的认证方式由Servlet规范定制,服务端要存储session信息需要占用内存资源,客户端需要支持cookie; ②基于token的方式则一般不需要服务端存储token,并且不限制客户端的存储方式。如今移动互联网时代更多类型的客户端需要接入系统,系统多是采用前后端分离的架构进行实现,所以基于token的方式更适合。

什么是授权:

还拿微信来举例子,微信登录成功后用户即可使用微信的功能,比如,发红包、发朋友圈、添加好友等,没有绑定银行卡的用户是无法发送红包的,绑定银行卡的用户才可以发红包,发红包功能、发朋友圈功能都是微信的资源即功能资源,用户拥有发红包功能的权限才可以正常使用发送红包功能,拥有发朋友圈功能的权限才可以使用发朋友圈功能,这个根据用户的权限来控制用户使用资源的过程就是授权。 认证是为了保证用户身份的合法性,授权则是为了更细粒度的对隐私数据进行划分,授权是在认证通过后发生的,控制不同的用户能够访问不同的资源。 授权: 授权是用户认证通过根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有 权限则拒绝访问。

授权的数据模型:

如何进行授权即如何对用户访问资源进行控制,首先需要学习授权相关的数据模型。 授权可简单理解为Who对What(which)进行How操作,包括如下: ①Who,即主体(Subject),主体一般是指用户,也可以是程序,需要访问系统中的资源。 What,即资源(Resource),如系统菜单、页面、按钮、代码方法、系统商品信息、系统订单信息等。 ②系统菜单、页面、按钮、代码方法都属于系统功能资源,对于web系统每个功能资源通常对应一个URL;系统商品信息、系统订单信息都属于实体资源(数据资源),实体资源由资源类型和资源实例组成,比如商品信息为资源类型,商品编号 为001的商品为资源实例。 How,权限/许可(Permission),规定了用户对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个代码方法的调用权限、编号为001的用户的修改权限等,通过权限可知用户对哪些资源都有哪些操作许可。 ③主体、资源、权限关系如下图: 在这里插入图片描述 ④主体、资源、权限相关的数据模型如下: 主体(用户id、账号、密码、...) 资源(资源id、资源名称、访问地址、...) 权限(权限id、权限标识、权限名称、资源id、...) 角色(角色id、角色名称、...) 角色和权限关系(角色id、权限id、...) 主体(用户)和角色关系(用户id、角色id、...) ⑤主体(用户)、资源、权限关系如下图: 在这里插入图片描述 ⑥通常企业开发中将资源和权限表合并为一张权限表,如下: 资源(资源id、资源名称、访问地址、...) 权限(权限id、权限标识、权限名称、资源id、...) ⑦合并为: 权限(权限id、权限标识、权限名称、资源名称、资源访问地址、...) 修改后数据模型之间的关系如下图: 在这里插入图片描述

RBAC:

如何实现授权? ①业界通常基于RBAC实现授权。 基于角色的访问控制 ①RBAC基于角色的访问控制(Role-Based Access Control)是按角色进行授权,比如:主体的角色为总经理可以查询企业运营报表,查询员工工资信息等,访问控制流程如下: 在这里插入图片描述 ②根据上图中的判断逻辑,授权代码可表示如下: 根据下边的例子发现,当需要修改角色的权限时就需要修改授权的相关代码,系统可扩展性差。 if(主体.hasRole("总经理角色id")){ 查询工资 } 如果上图中查询工资所需要的角色变化为总经理和部门经理,此时就需要修改判断逻辑为“判断用户的角色是否是总经理或部门经理”,修改代码如下: if(主体.hasRole("总经理角色id") || 主体.hasRole("部门经理角色id")){ 查询工资 } 复制代码 基于资源的访问控制 ①RBAC基于资源的访问控制(Resource-Based Access Control)是按资源(或权限)进行授权,比如:用户必须具有查询工资权限才可以查询员工工资信息等,访问控制流程如下: 在这里插入图片描述 ②优点:系统设计时定义好查询工资的权限标识,即使查询工资所需要的角色变化为总经理和部门经理也不需要修改授权代码,系统可扩展性强。 ③根据上图中的判断,授权代码可以表示为: if(主体.hasPermission("查询工资权限标识")){ 查询工资 } 复制代码 总结来说就是基于资源比基于角色拥有更小的粒度,因此更好扩展。 基于Session的认证方式

认证流程:

基于Session认证方式的流程是,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话),而发给客户端的sesssion_id 存放到 cookie 中,这样用客户端请求时带上 session_id 就可以验证服务器端是否存在 session数据,以此完成用户的合法校验。当用户退出系统或session过期销毁时,客户端的session_id也就无效了。 下图是session认证方式的流程图: 在这里插入图片描述 基于Session的认证机制由Servlet规范定制,Servlet容器已实现,用户通过HttpSession的操作方法即可实现,如下是HttpSession相关的操作API。 方法含义HttpSessiongetSession(Boolean create) 获取当前HttpSession对象voidsetAttribute(String name,Object value) 向session中存放对象objectgetAttribute(String name) 从session中获取对象voidremoveAttribute(String name); 移除session中对象voidinvalidate() 使HttpSession失效略... Demo要点: ①实现会话功能:首先在UserDto中定义一个SESSION_USER_KEY,作为Session中存放登录用户信息的key。 ②授权功能思路: 匿名用户(未登录用户)访问拦截:禁止匿名用户访问某些资源。 登录用户访问拦截:根据用户的权限决定是否能访问某些资源。 ③实现授权功能:为了实现这样的功能,我们需要在UserDto里增加权限属性( Set类型),用于表示该登录用户所拥有的权限。 Spring Security简介

Spring Security介绍:

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是Spring生态系统中的一员,因此它伴随着整个Spring生态系统不断修正、升级,在spring boot项目中加入spring security更是十分简单,使用Spring Security 减少了为企业系统安全控制编写大量重复代码的工作。 引入以下依赖:在security-springmvc的基础上增加spring-security的依赖: org.springframework.security spring‐security‐web 5.1.4.RELEASE org.springframework.security spring‐security‐config 5.1.4.RELEASE 复制代码 Spring Security初始化,这里有两种情况: ①如果您不使用 Spring 或 Spring MVC,则需要将WebSecurityConfig传递到超类中,以确保配置被接受。(写一个类然后继承超类进行添加) ②如果我们在应用程序的其他地方使用 Spring,则可能已经有一个WebApplicationInitializer用来加载 Spring 配置。如果我们使用以前的配置,将会得到一个错误。相反,我们应该使用现有的ApplicationContext注册 Spring Security。(在已有的类上进行添加) --------不使用 Spring 或 Spring MVC-------- public class SpringSecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer { public SpringSecurityApplicationInitializer() { super(WebSecurityConfig.class); } } --------使用 Spring-------- public class MvcWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return new Class[] { WebSecurityConfig.class }; } // ... other overrides ... } 复制代码 WebSecurityConfig详解: ①WebSecurityConfigurerAdapter在configure(HttpSecurity http)方法中提供了默认配置: 确保对我们应用程序的任何请求都需要对用户进行身份验证 允许用户使用基于表单的登录进行身份验证 允许用户使用 HTTP Basic 身份验证进行身份验证 ②使用and()方法表示等效于关闭 XML 标记的 Java 配置,该方法允许我们 continue 配置父级。 @EnableWebSecurity @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { } 复制代码 springSecurity默认提供认证页面(登录,登出),不需要额外开发。当然我们也可以自定义配置(大部分): ①使用WebSecurityConfigurerAdapter时,将自动应用登录功能。默认设置是访问 URL /login将通过以下方式登录用户。 ②使用WebSecurityConfigurerAdapter时,将自动应用注销功能。默认设置是访问 URL /logout将通过以下方式注销用户。 ③除此之外还可以配置登录成功的页面,登录失败的页面以及注销成功的页面。 授权请求:我们可以通过将多个子级添加到http.authorizeRequests()方法中来为 URL 指定自定义要求: (1) http.authorizeRequests()方法有多个子级,每个匹配器均按声明 Sequences 考虑。 (2) 我们指定了任何用户都可以访问的多个 URL 模式。具体来说,如果 URL 以“/resources /”开头,等于“/signup”或等于“/about”,则任何用户都可以访问请求。 (3) 任何以“/admin /”开头的 URL 都将限于角色为“ ROLE_ADMIN”的用户。您将注意到,由于我们正在调用hasRole方法,因此无需指定“ ROLE_”前缀。 (4) 任何以“/db /”开头的 URL 都要求用户同时具有“ ROLE_ADMIN”和“ ROLE_DBA”。您会注意到,由于我们使用的是hasRole表达式,因此无需指定“ ROLE_”前缀。 (5) antMatchers("/r/r2").hasAuthority("p2")表示:访问/r/r2资源的 url需要拥有p2权限。 (6) 尚未匹配的任何 URL 仅要求对用户进行身份验证 protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() (1) .antMatchers("/resources/**", "/signup", "/about").permitAll() (2) .antMatchers("/admin/**").hasRole("ADMIN") (3) .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") (4) .antMatchers("/r/r2").hasAuthority("p2") (5) .anyRequest().authenticated() (6) .and() // ... .formLogin(); } 复制代码 Authentication认证: ①内存中身份验证:从内存中查 ②JDBC 身份验证:从数据库中查 ③LDAP 认证:从配置文件中查 //配置用户信息服务 @Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build()); manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build()); return manager; } 复制代码 密码编码:Spring Security 的PasswordEncoder接口用于执行密码的单向转换,以允许安全地存储密码。鉴于PasswordEncoder是一种单向转换,因此在密码转换需要采用两种方式(即存储用于向数据库进行身份验证的凭据)时并不适用。通常,PasswordEncoder用于存储需要与认证时用户提供的密码进行比较的密码。 //密码加密器 @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } 复制代码

SpringSecurity集成SpringBoot:

Spring Boot是一套Spring的快速开发框架,基于Spring 4.0设计,使用Spring Boot开发可以避免一些繁琐的工程搭建和配置,同时它集成了大量的常用框架,快速导入依赖包,避免依赖包的冲突。Spring Boot提供spring-boot-starter-security用于开 发Spring Security应用。 由于Spring boot starter自动装配机制,这里无需使用@EnableWebSecurity,WebSecurityConfig内容如下: @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { //内容跟Spring security入门程序一致 } 复制代码 SpringSecurity详解

结构总览:

Spring Security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源。根据前边知识的学习,可以通过Filter或AOP等技术来实现,SpringSecurity对Web资源的保护是靠Filter实现的,所以从这个Filter来入手,逐步深入Spring Security原理。

当初始化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)进行处理,下图是FilterChainProxy相关类的UML图示。在这里插入图片描述

spring Security功能的实现主要是由一系列过滤器链相互配合完成。 在这里插入图片描述

下面介绍过滤器链中主要的几个过滤器及其作用: ①SecurityContextPersistenceFilter 这个Filter是整个拦截过程的入口和出口(也就是第一个和最后一个拦截 器),会在请求开始时从配置好的 SecurityContextRepository 中获取 SecurityContext,然后把它设置给 SecurityContextHolder。在请求完成后将 SecurityContextHolder 持有的 SecurityContext 再保存到配置好 的 SecurityContextRepository,同时清除 securityContextHolder 所持有的 SecurityContext; ②UsernamePasswordAuthenticationFilter 用于处理来自表单提交的认证。该表单必须提供对应的用户名和密 码,其内部还有登录成功或失败后进行处理的 AuthenticationSuccessHandler 和 AuthenticationFailureHandler,这些都可以根据需求做相关改变; ③FilterSecurityInterceptor 是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问,前 面已经详细介绍过了; ④ExceptionTranslationFilter 能够捕获来自 FilterChain 所有的异常,并进行处理。但是它只会处理两类异常: AuthenticationException 和 AccessDeniedException,其它的异常它会继续抛出。

认证流程: 在这里插入图片描述

用户提交用户名、密码被SecurityFilterChain中的 过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证 认证成功后, AuthenticationManager 身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,实例。身份信息,细节信息,但密码通常会被移除) SecurityContextHolder 安全上下文容器将第3步填充了信息的,通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。 ①可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它 的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。咱们知道web表单的对应的AuthenticationProvider实现类为 DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终 AuthenticationProvider将UserDetails填充至Authentication。 在这里插入图片描述

AuthenticationProvider(认证流程提供者):

通过前面的Spring Security认证流程我们得知,认证管理器(AuthenticationManager)委托AuthenticationProvider完成认证工作。 AuthenticationProvider是一个接口,定义如下: public interface AuthenticationProvider { Authentication authenticate(Authentication authentication) throws AuthenticationException; boolean supports(Class var1); } 复制代码 authenticate()方法定义了认证的实现过程,它的参数是一个Authentication,里面包含了登录用户所提交的用户、密码等。而返回值也是一个Authentication,这个Authentication则是在认证成功后,将用户的权限及其他信息重新组装后生成。 Spring Security中维护着一个列表,存放多种认证方式,不同的认证方式使用不同的AuthenticationProvider。如使用用户名密码登录时,使用AuthenticationProvider1,短信登录时使用AuthenticationProvider2等等这样的例子很多。 每个AuthenticationProvider需要实现supports()方法来表明自己支持的认证方式,如我们使用表单方式认证,在提交请求时Spring Security会生成UsernamePasswordAuthenticationToken,它是一个Authentication,里面封装着用户提交的用户名、密码信息。而对应的,哪个AuthenticationProvider来处理它? 我们在DaoAuthenticationProvider的基类AbstractUserDetailsAuthenticationProvider发现以下代码: public boolean supports(Class authentication) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } 复制代码 也就是说当web表单提交用户名密码时,Spring Security由DaoAuthenticationProvider处理。 最后,我们来看一下Authentication(认证信息)的结构,它是一个接口,我们之前提到的 UsernamePasswordAuthenticationToken就是它的实现之一: (1)Authentication是spring security包中的接口,直接继承自Principal类,而Principal是位于包中的。它是表示着一个抽象主体身份,任何主体都有一个名称,因此包含一个getName()方法。 (2)getAuthorities(),权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系 列字符串。 (3)getCredentials(),凭证信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全。 (4)getDetails(),细节信息,web应用中的实现接口通常为 WebAuthenticationDetails,它记录了访问者的ip地 址和sessionId的值。 (5)getPrincipal(),身份信息,大部分情况下返回的是UserDetails接口的实现类,UserDetails代表用户的详细信息,那从Authentication中取出来的UserDetails就是当前登录用户信息,它也是框架中的常用接口之一。 public interface Authentication extends Principal, Serializable { (1) Collection


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有