暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring Cloud学习笔记——Spring Security与OAuth2

CodeWu 2021-06-23
1299

Security

Spring Security

Spring Security提供了一套完整的声明式安全访问控制方案。为Spring Boot和Spring Cloud应用提供安全保护相关功能。

核心概念

名称
描述

Principle

用户对象

Authority

用户角色

Permission

授权,对角色拥有的权限进行描述

在Spring Security中,Principle(用户对象)、Authority(用户角色)、Permission(授权)都是独立的概念,三者之间没有必然联系(数据库映射关系),需要通过配置信息来定义三者之间的关系。

认证与授权

安全方面的实现方案通常由认证(Authentication)和授权(Authorization)两个部分组成。

认证(Authentication)

建立系统使用者信息(Principai)的过程。要求系统用户提供用户名和密码,通过校验用户名和密码的正确性来完成认证成功或认证失败。

Spring Security进行认证的步骤如下:

  1. 系统用户通过登录表单输入用户名和密码信息,提交登录表单进行登录请求。

  2. UsernamePasswordAuthenticationFilter获取到表单输入的用户名和密码信息,封装为待认证对象(Authentication)。

  3. 认证管理对象AuthenticationManager对未进行认证操作的对象通过AuthenticationProvider接口执行认证操作,AuthenticationProvider提供了多种登录认证方式。

  4. 在AuthenticationProvider提供的多种登录认证方式中,使用UserDetailService接口实现类的loadUserByUsername方法执行具体的登录认证操作,在该方法中我们可以自己实现按照登录名和密码信息校验,返回校验通过的登录用户详情(UserDetails)。

  5. 将校验通过的登陆用户信息设置到安全上下文(SecurityContext)。


    授权(Authorization)

    不同用户具有的系统使用权限不同,系统会为不同的用户分配不同的角色,每个系统角色具备一系列的系统权限。授权系统会判断某个用户是否在微服务系统中具备调用服务实例的权限。

    在微服务系统实践过程中,最好将认证/授权系统单另抽取成独立的服务实例。

    Spring Cloud Security

    用于构建微服务的安全应用程序和服务,可以轻松实现微服务系统架构下的统一安全认证与授权。包含以下组件

组件名
组件描述

spring-cloud-security

为Zuul、Feign、OAuth2的资源服务器的token提供相关支持

spring-cloud-starter-security

管理在Spring Cloud中使用Spring Security的依赖

spring-cloud-starter-oauth2

管理在Spring Cloud中使用Spring Security OAuth2依赖

OAuth2.0

OAuth2.0是一个标准的授权协议。服务于用户资源和第三方应用之间,使得第三方应用无法直接访问用户资源,需要访问用户资源需要通过提供凭证获得OAuth2.0授权, 从而起到保护用户资源的作用。

如果资源所有者允许第三方应用访问资源,除了将用户名和密码告知第三方应用,让第三方应用以资源所有者身份访问资源,还可以通过授权码的方式让第三方应用对资源进行访问。

OAuth2.0角色

角色名
角色描述

授权服务提供方(Authorization Server)

认证服务器,进行访问的认证和授权

资源所有者(Resource Owner)

系统用户

资源服务器(Resource Server)

存放用户资源

客户端(Client)

第三方应用

OAuth2.0运行流程

  1. 系统用户打开客户端,请求资源拥有者给予授权。

  2. 资源拥有者同意给客户端授权。

  3. 客户端使用上一个步骤获取到的授权,向认证服务器申请令牌。

  4. 认证 服务器对授权信息进行认证,认证通过发放令牌。

  5. 客户端使用申请到的令牌向资源服务器申请获取资源。

  6. 资源服务器确认令牌无误,向客户端开放资源。

    客户端授权模式

    • 简化模式

    客户端不通过第三方应用服务器,直接在浏览器中向认证服务器申请令牌。所有步骤在浏览器中完成,令牌对访问者可见,且客户端不需要认证。执行流程如下:

    1. 客户端通过浏览器将用户导向认证服务器。包含如下参数:


      参数名参数描述
      response_type授权类型(必填项),此处固定值为"token"
      client_id
      客户端标识(必填项)
      redirect_uri重定向URI(选填项)
      scope
      授权范围(选填项)
      state
      客户端状态(必填项,否则存在CSRF漏洞),认证服务器将用户代理重定向时需携带该参数
    2. 用户决定是否授权客户端。

    3. 如果用户给予授权,认证服务器将用户导向客户端的"重定向URI",并在该URI的Hash参数值部分包含访问令牌。认证服务器响应给客户端的URI中包括以下参数:


      参数名
      参数描述
      access_token
      访问令牌(必填项)
      token_type
      令牌类型(必填项)大小写不敏感
      expires_in
      令牌过期时间(秒),省略该参数需使用其他方式设置过期时间
      scope
      权限范围,如果与客户端申请时的范围一致可省略该参数
      state客户端状态,认证服务器响应与客户端请求时参数内容一致
    4. 客户端通过浏览器向资源服务器发送请求。

    5. 资源服务器返回一个网页,其中包括第三步收到的Hash值(参数及对应内容)。

    6. 浏览器执行上一步网页中的脚本文件,提取出Hash值相关的令牌内容。

    7. 浏览器将获取到的令牌内容传递给客户端。

    • 密码模式

      用户向客户端提供用户名和密码信息,客户端使用用户名和密码信息向认证服务器申请授权令牌并返回给用户,用户使用授权令牌访问用户资源。


    1. 系统用户访问客户端,需要提供用户名和密码信息。

    2. 客户端将用户名和密码信息发送至认证服务器,申请令牌。需要包括如下参数


      参数名
      参数描述
      grant_type
      授权类型(必填项),此处固定值为"password"
      username
      用户名(必填项)
      password
      密码(必填项)
      scope
      权限范围(选填项)
    3. 认证服务器确认无误,向客户端提供访问令牌。

    4. 系统用户通过客户端携带令牌信息访问资源服务器获取用户资源。

    • 客户端模式

      客户端以自己的名义向认证服务器进行认证,不存在授权问题。


    1. 客户端向认证服务器进行身份验证,并申请一个访问令牌。包含参数如下


      参数名
      参数描述
      grant_type授权类型(必填项),此处固定值为"clientcredentials"
      scope
      权限范围(选填项)
    2. 认证服务器确认无误后向客户端提供访问令牌。

    • 授权码模式

      客户端通过后台服务器与认证服务器交互。


    1. 用户访问客户端。

    2. 客户端利用重定向将用户导向认证服务器申请认证。包含如下参数:


      参数名
      参数描述
      response_type
      授权类型(必填项),此处固定值为"code"
      client_id
      客户端标识(必填项)
      redirect_uri
      重定向URI(选填项)
      scope申请的授权范围(选填项)
      state客户端状态,可以使用任意内容作为参数值(建议动态内容,否则存在CSRF漏洞),认证服务器会返回请求参数原值
    3. 用户选择是否给客户端授权。

    4. 如果用户同意授权,认证服务器会将用户导向至步骤2中设置的重定向URI参数地址,并附带一个授权码。认证服务器响应给客户端的URI中包含如下参数:


      参数名
      参数描述
      code
      授权码(必填项)。有效期很短(几分钟),客户端只能使用该授权码一次,否则会被认证服务器拒绝访问。该授权码与步骤2中的客户端标识和重定向URI为对应关系
      state如果步骤2中包含该参数,认证服务器响应信息也包含该参数且参数值一致
    5. 客户端收到授权码,附上"重定向URI",向认证服务器申请令牌。包含如下参数:


      参数名
      参数描述
      grant_type授权类型(必填项),此处固定值为"authorization_code"
      code
      步骤4中获取到的授权码(必填项)
      redirect_uri重定向URI(必填项),参数值与步骤2中重定向URI参数值一致
      client_id客户端ID(必填项)
    6. 认证服务器核对授权码和重定向URI,确认无误后向客户端发送访问令牌(access token)和更新令牌(refresh token)。认证服务器的响应内容中包含如下参数:


      参数名
      参数描述
      access_token
      访问令牌(必填项)
      token_type
      令牌类型(必填项,参数值内容bearer或mac)
      expires_in
      过期时间(秒)
      refresh_token
      刷新令牌(必填项)
      scope
      授权范围。如果该范围与客户端申请范围一致可省略参数值

      如果在用户访问时客户端的访问令牌已经过期,用户需要用更新令牌重新申请一个访问令牌。客户端发出更新令牌的请求参数如下:

      参数名
      参数描述
      grant_type
      授权类型(必填项),此处固定值为"authorization_code"
      refresh_token
      刷新令牌(必填项),参数值与步骤6中refresh_token值一致
      scope
      申请的授权范围(必填项),不得超过步骤6中的授权范围参数值,省略该参数值默认与步骤6授权范围参数值一致

    授权模式总结

    授权模式
    使用场景令牌刷新
    应用范围
    简化模式
    WEB浏览器
    不支持APP
    密码模式
    遗留系统支持
    受信任系统
    授权码模式
    第三方应用支持
    服务端应用之间
    客户端模式
    接口调用不支持API访问

    Spring Cloud Security实现OAuth2

    OAuth2.0服务提供端

    在OAuth2.0中,服务提供端分为"授权服务"和"资源服务"两个角色,通过管理和验证OAuth2.0令牌对资源进行保护和服务,负责将受保护的资源暴露出去。

    Spring Security OAuth2.0将"授权服务"和"资源服务"分别放在多个应用中,可以为一个"授权服务"配置多个"资源服务"。获取令牌(Token)的请求由Spring MVC控制器端点处理,访问受保护资源通过标准的Spring Security请求过滤器处理。

    Spring Security过滤器实现OAuth2.0授权服务器必须提供以下两个端点


    端点名称
    端点描述
    AuthorizationEndpoint
    用于授权服务请求,默认URI为/oauth/authrize
    TokenEndpoint
    用于获取访问令牌(access token)请求,默认URI为/oauth/token

    授权服务器

    授权服务器搭建的过程中,需要考虑客户端详细信息及令牌服务的具体实现。

    在Spring Cloud Security中,可以通过注解@EnableAuthorizationServer来启用授权服务器。并需要实现以下配置信息

    配置
    配置描述
    ClientDetailServiceConfigurer
    配置客户端信息
    AuthorizationServerEndpointsConfigurer
    配置授权token节点和token服务
    AuthorizationServerSecretConfigurer
    配置token节点安全策略
    • ClientDetailServiceConfigurer

      用来配置客户端详情信息,可以基于内存和数据库方式管理客户端配置信息,配置内容如下:

      配置项配置描述
      clientId
      用来标识客户端(必须配置)
      secret
      客户端安全码(SpringBoot2.0以上必须配置此项)
      scope
      限制客户端的访问范围(为空客户端拥有全部访问范围)
      authorizedGrantTypes
      客户端使用的授权类型
      authorities
      客户端可以使用的权限(基于Spring Security Authorities)

      基于内存存储客户端配置信息

    @Configuration
    public class ClientDetailServiceConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    /**
    * 将客户端配置存储于内存中
    * @param configurer 客户端详情配置类
    */
    public void clientDetailConfig(ClientDetailsServiceConfigurer configurer) throws Exception
    {
    //设置客户端配置信息存储于内存中,并设置客户端标识
    configurer.inMemory().withClient("clientInMemory")
    .secret(passwordEncoder.encode("123456"))//使用BCryptPasswordEncoder对密码进行加密
    .authorizedGrantTypes("password")//授权访问模式
    .scopes("all")//设置访问范围
    .accessTokenValiditySeconds(36000);//token有效时间


    }
    }


    • AurhorizationServerEndpointsConfigurer

    用来配置授权(Authorization)、令牌(Token)访问端点、令牌服务(Token Service)。默认情况下,AuthorizationServerEndpointsConfigurer开启了所有的验证类型,除了密码类型的验证(只有配制了authenticationManager才会开启)。配置内容如下:

    配置项
    配置描述
    authenticationManager

    密码认证配置项,配置该项密码认证模式才会开启

    userDetailService

    获取用户详情信息配置项
    authorizationCodeService
    验证码服务配置项
    implicitGrantService
    配置管理implicit验证的状态
    tokenGranter
    管理token granter配置项 

    除了上述配置信息,还需要配置token的管理策略,目前支持如下策略:

    策略名策略描述
    InMemoryTokenStore
    token内容存储于内存中
    JdbcTokenStore

    Token存储于数据库中(需引入spring-jdbc依赖包并配置数据源)

    JWTTokenStore

    采用JWT形式,未做任何存储(JWT本身包含,需引入spring-jwt依赖)

    • AuthorizationServerSecretConfigurer

    用来配置令牌端点安全约束。主要配置内容如下

    配置项
    配置描述
    ClientDetailService

    根据客户端标识获取客户端详情信息(loadClientByClientId)

    UserDetailService

    根据用户名获取用户详情信息

    ClientDetailsUserDetailsService

    实现UserDetailsService接口, 持有ClientDetailsService接口属性,获取客户端详情时重写loadClientByClientId方法,将用户名作为参数

    ClientCredentialsTokenEndpointFilter

    通过拦截/oauth/token获取到clientId和clientSecret参数进行用户认证校验

    资源服务器

    资源服务器(Resource Server)提供了受OAuth2保护的资源(API接口)。Spring OAuth2提供了实现此保护功能的Spring Security认证过滤器。在加了@Configuration注解的配置类上加上@EnableResourceServer注解,启用资源服务器相关功能。

    OAuth2Client

    用于访问被OAuth2保护起来的资源。客户端需要提供用于存储用户的授权码和访问令牌的机制,需要配置以下内容:

    配置项
    配置描述

    Protected Resource Configuration

    受保护资源配置

    Client Configuration

    客户端配置
    • 受保护资源配置

    使用OAuth2ProtectedResourceDetails类型的Bean来定义受保护的资源,具备如下属性:

    属性名
    属性描述
    id
    受保护资源标识,无需配置,保持默认内容
    clientId

    OAuth2 Client标识(与授权服务器配置的客户端详情信息中的clientId内容对应)

    clientSecret

    客户端密码(与授权服务器配置的客户端详情信息中的secret内容对应)

    accessTokenUri

     获取Token的API节点

    scope
    客户端访问范围
    clientAuthenticationScheme

    客户端验证类型,分别为Http Basic和Form,默认Http Basic

    userAuthorizationUri

    如果用户需要授权访问资源,用户将被重定向到认证的UrI


    • 客户端配置

    使用@EnableOAuth2Client注解简化配置,需要配置以下内容:

    配置项
    配置描述
    oauth2ClientContextFilter
    存储当前请求和上下文请求
    AccessTokenRequest
    获取授权令牌请求Bean


    文章转载自CodeWu,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论