微服务[学成在线] day16:基于Spring Security Oauth2开发认证服务

本文介绍了基于Spring Security Oauth2开发认证服务的详细流程,涵盖用户需求分析、Oauth2授权码模式、Spring Security Oauth2的配置与实现、资源服务授权及JWT令牌的生成与验证。通过实例展示了如何搭建认证服务器、申请令牌、资源服务授权以及使用JWT进行身份验证,旨在帮助读者理解Oauth2的工作原理并实现在项目中的应用。
摘要由CSDN通过智能技术生成

😎 知识点概览

为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。

本章节为【学成在线】项目的 day16 的内容

  • 学习 Spring Security + Oauth2 基本概念以及实现过程。
  • 学习 Oauth2 的基本应用场景,这里主要是通过 Oauth2 的密码模式来实战。
  • 初识 JWT 令牌。
  • 本章节的最后通过 Spring Security Oauth2 完成了认证服务的基本实现,但授权还没做。

目录

内容会比较多,小伙伴们可以根据目录进行按需查阅。

一、用户需求分析

0x01 用户认证与授权

截至目前,项目已经完成了在线学习功能,用户通过在线学习页面点播视频进行学习。

如何去记录学生的学习过程呢?

要想掌握学生的学习情况就需要知道用户的身份信息,记录哪个用户在什么时间学习什么课程;如果用户要购买课程也需要知道用户的身份信息。所以,去管理学生的学习过程最基本的要实现用户的身份认证。

什么是用户身份认证?

用户身份认证即用户去访问 系统资源 时系统要求验证用户的身份信息,身份合法方可继续访问。常见的用户身份认证表现形式有:用户名密码登录,指纹打卡等方式。

什么是用户授权?

用户认证通过后去访问系统的资源,系统会判断用户是否拥有访问资源的 权限,只允许访问有权限的系统资源,没有权限的资源将无法访问,这个过程叫用户授权。

0x02 单点登录需求

本项目包括多个子项目,如:学习系统,教学管理中心、系统管理中心等,为了提高用户体验性需要实现用户只认证一次便可以在多个拥有访问权限的系统中访问,这个功能叫做单点登录。

引用百度百科:单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。

SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
下图是 SSO 的示意图,用户登录学成网一次即可访问多个系统。

0x03 第三方认证需求

作为互联网项目难免需要访问外部系统的资源,同样本 服务 也要访问 其他服务 的资源接口。

一个微信用户没有在学成在线注册,本系统可以通过请求微信系统来验证该用户的身份,验证通过后该用户便可在本系统学习,它的基本流程如下:

从上图可以看出,微信不属于本系统,本系统并没有存储微信用户的账号、密码等信息,本系统如果要获取该用户的基本信息则需要首先通过微信的认证系统(微信认证)进行认证,微信认证通过后本系统便可获取该微信用户的基本信息,从而在本系统将该微信用户的头像、昵称等信息显示出来,该用户便不用在本系统注册却可以直接学习。

什么是第三方认证(跨平台认证)?

当需要访问第三方系统的资源时需要首先通过第三方系统的认证(例如:微信认证),由第三方系统对用户认证通过,并授权资源的访问权限。

二、用户认证技术方案

0x01 单点登录技术方案

分布式系统要实现单点登录,通常将认证系统独立抽取出来,并且将用户身份信息存储在单独的存储介质,比如:MySQLRedis,考虑性能要求,通常存储在 Redis 中,如下图:

单点登录的特点是:

1、认证系统为独立的系统。

2、各个 子系统 通过 Http 或其它协议与认证系统通信,完成用户认证。

3、用户身份信息存储在 Redis 集群。

Java 中有很多用户认证的框架都可以实现单点登录:

1、Apache Shiro.

2、CAS

3、Spring security CAS

0x02 Oauth2认证

认证流程

第三方认证技术方案最主要是解决认证协议的通用标准 问题,因为要实现 跨系统认证,各系统之间要遵循一定的接口协议。

OAUTH 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以使用 OAUTH 认证服务,任何服务提供商都可以实现自身的 OAUTH 认证服务,因而 OAUTH 是开放的。业界提供了 OAUTH 的多种实现如 PHPJavaScriptJavaRuby 等各种语言开发包,大大节约了程序员的时间,因而 OAUTH 是简易的。互联网很多服务如 Open API,很多大公司如 GoogleYahooMicrosoft 等都提供了 OAUTH 认证服务,这些都足以说明 OAUTH 标准逐渐成为开放资源授权的标准。

Oauth 协议目前发展到 2.0 版本,1.0 版本过于复杂,2.0 版本已得到广泛应用。

参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin

Oauth协议:https://tools.ietf.org/html/rfc6749

下边分析一个Oauth2认证的例子,黑马程序员网站使用微信认证的过程:

从流程图可以看出,用户首先需要访问黑马程序员的登录页面,登录页面中会有一个第三方登录的选项,例如选择微信来进行登录。

点击微信登录后,黑马程序员网站会向微信获取到一个认证授权的页面,并返回给客户端,客户端自动跳转到该 认证授权页面 进行微信的认证,当用户通过微信授权认证成功后,微信的认证服务器会返回一个授权码到客户端,客户端使用授权码向微信认证服务器申请 认证token,当用户获取到 token 后,会携带该 token 值去请求黑马程序员网站,黑马程序员通过该token向微信服务器获取到用户的微信信息后,黑马程序员网站才能确定该用户是可信的。

具体流程演示如下:

1、客户端请求第三方授权

用户进入黑马程序的登录页面,点击微信的图标以微信账号登录系统,用户是自己在微信里信息的资源拥有者。

点击“微信”出现一个二维码,此时用户扫描二维码,开始给黑马程序员授权。

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

资源拥有者扫描二维码表示资源拥有者同意给客户端授权,微信会对资源拥有者的身份进行验证, 验证通过后,微信会询问用户是否给授权黑马程序员访问自己的微信数据,用户点击 “确认登录”表示同意授权,微信认证服务器会颁发一个授权码,并重定向到黑马程序员的网站。

3、客户端获取到授权码,请求认证服务器申请令牌

此过程用户看不到,客户端应用程序请求认证服务器,请求携带授权码。

4、认证服务器向客户端响应令牌

认证服务器验证了客户端请求的授权码,如果合法则给客户端颁发令牌,令牌是客户端访问资源的通行证。此交互过程用户看不到,当客户端拿到令牌后,用户在黑马程序员看到已经登录成功。

5、客户端请求资源服务器的资源

客户端携带令牌访问资源服务器的资源。黑马程序员网站携带令牌请求访问微信服务器获取用户的基本信息。

6、资源服务器返回受保护资源

资源服务器校验令牌的合法性,如果合法则向用户响应资源信息内容。
注意:资源服务器和认证服务器可以是一个服务也可以分开的服务,如果是分开的服务资源服务器通常要请求认证服务器来校验令牌的合法性。

Oauth2.0 认证流程如下:

引自 Oauth2.0 协议 rfc6749 https://tools.ietf.org/html/rfc6749

Oauth2包括以下角色:

1、客户端

本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源,比如:学成在线Android客户端、学成在线Web客户端(浏览器端)、微信客户端等。

2、资源拥有者

通常为用户,也可以是应用程序,即该资源的拥有者。

3、授权服务器(也称认证服务器)
用来对资源拥有的身份进行认证、对访问资源进行授权。客户端要想访问资源需要通过认证服务器由资源拥有者授权后方可访问。

4、资源服务器
存储资源的服务器,比如,学成网用户管理服务器存储了学成网的用户信息,学成网学习服务器存储了学生的学习信息,微信的资源服务存储了微信的用户信息等。客户端最终访问资源服务器获取资源信息。

Oauth2在本项目的应用

Oauth2是一个标准的开放的授权协议,应用程序可以根据自己的要求去使用 Oauth2,本项目使用 Oauth2 实现如下目标:

1、学成在线访问第三方系统的资源

2、外部系统访问学成在线的资源

3、学成在线前端(客户端) 访问学成在线微服务的资源。

4、学成在线微服务之间访问资源,例如:微服务A 访问 微服务B 的资源,B 访问 A 的资源。

0x03 Spring Security Oauth2 认证解决方案

本项目采用 Spring security + Oauth2 完成用户认证及用户授权,Spring security 是一个强大的和高度可定制的身份验证和访问控制框架,Spring security 框架集成了Oauth2 协议,下图是项目认证架构图:

1、用户请求认证服务完成认证。

2、认证服务下发用户身份令牌,拥有身份令牌表示身份合法。

3、用户携带令牌请求资源服务,请求资源服务必先经过网关。

4、网关校验用户身份令牌的合法,不合法表示用户没有登录,如果合法则放行继续访问。

5、资源服务获取令牌,根据令牌完成授权。

6、资源服务完成授权则响应资源信息。

三、Spring Security Oauth2 研究

0x01 目标

本项目认证服务基于 Spring Security Oauth2 进行构建,并在其基础上作了一些扩展,采用 JWT 令牌机制,并自定义了用户身份信息的内容。 本教程的主要目标是学习在项目中集成Spring Security Oauth2 的方法和流程,通过 Spring Security Oauth2 的研究需要达到以下目标:

1、理解 Oauth2 的授权码认证流程及密码认证的流程。

2、理解 Spring Security Oauth2 的工作流程。

3、掌握资源服务集成 Spring Security 框架完成 Oauth2 认证的流程。

0x02 搭建认证服务器

导入基础工程

导入 资料 目录下的 xc-service-ucenter-auth 工程,该工程是基于Spring Security Oauth2 的一个二次封装的工程,导入此工程研究 Oauth2 认证流程。

创建数据库

导入资料目录下的 xc_user.sql,创建用户数据库

oauth_ 开头的表都是 Spring Security 自带的表。

本项目中 Spring Security 主要使用 oauth_client_details 表:

  • client_id:客户端id

  • resource_ids:资源id(暂时不用)

  • client_secret:客户端密码

  • scope:范围

  • access_token_validity:访问token的有效期(秒)

  • refresh_token_validity:刷新token的有效期(秒)

  • authorized_grant_type:授权类型,

    • authorization_code
    • password
    • refresh_token
    • client_credentials

0x03 Oauth2授权码模式

Oauth2 有以下授权模式:

  • 授权码模式(Authorization Code)

  • 隐式授权模式(Implicit)

  • 密码模式(Resource Owner PasswordCredentials)

  • 客户端模式(Client Credentials)

其中授权码模式和密码模式应用较多,本小节介绍授权码模式。

授权码授权流程

上边例举的黑马程序员网站使用微信认证的过程就是授权码模式,流程如下:

1、客户端请求第三方授权

2、用户(资源拥有者)同意给客户端授权

3、客户端获取到授权码,请求认证服务器申请令牌

4、认证服务器向客户端响应令牌

5、客户端请求资源服务器的资源,资源服务校验令牌合法性,完成授权

6、资源服务器返回受保护资源

申请授权码

请求认证服务获取授权码:

GET 请求:

localhost:40400/auth/oauth/authorize?
client_id=XcWebApp&response_type=code&scop=app&redirect_uri=http://localhost

参数列表如下:

  • client_id:客户端 id,和授权配置类中设置的客户端id一致。
  • response_type:授权码模式固定为 code
  • scop:客户端范围,和授权配置类中设置的 scop一致。
  • redirect_uri:跳转 uri,当授权码申请成功后会跳转到此地址,并在后边带上code参(授权码)。

首次访问会跳转到登录页面:

输入账号和密码,点击 Login。

Spring Security 接收到请求会调用 UserDetailsService 接口的 loadUserByUsername 方法查询用户正确的密码。

oauth_client_details 表中配置认证的账号和密码,当然密码是加密后储存的,这里我们暂时先不关注,后面再讲解

账号密码为 XcWebAppXcWebApp

接下来进入授权页面:

点击 同意,接下来返回授权码:认证服务携带授权码跳转 redirect_uri

申请令牌

拿到授权码后,申请令牌。

POST 请求:http://localhost:40400/auth/oauth/token

参数如下:

  • grant_type:授权类型,填写authorization_code,表示授权码模式
  • code:授权码,就是刚刚获取的授权码,注意:授权码只使用一次就无效了,需要重新申请。
  • redirect_uri:申请授权码时的跳转url,一定和申请授权码时用的redirect_uri一致。

此链接需要使用 http Basic认证。

什么是 http Basic认证?

http 协议定义的一种认证方式,将客户端id和客户端密码按照 客户端ID:客户端密码 的格式拼接,并用 base64 编码,放在 header 中请求服务端,一个例子:

Authorization:Basic WGNXZWJBcHA6WGNXZWJBcHA=

WGNXZWJBcHA6WGNXZWJBcHA= 是 用户名:密码 的 base64 编码。

如果认证失败服务端会返回 401 Unauthorized

以上测试使用 postman 完成。

http basic认证:

客户端 Id 和客户端密码会匹配数据库 oauth_client_details 表中的客户端 id 及客户端密码。

POST 请求参数:

点击发送:

申请令牌成功。

  • access_token:访问令牌,携带此令牌访问资源
  • token_type:有 MAC TokenBearer Token两种类型,两种的校验算法不同,RFC 6750建议Oauth2采用 Bearer
  • Token(http://www.rfcreader.com/#rfc6750)。
  • refresh_token:刷新令牌,使用此令牌可以延长访问令牌的过期时间。
  • expires_in:过期时间,单位为秒。
  • scope:范围,与定义的客户端范围一致。

资源服务授权

1)授权流程

资源服务拥有要访问的受保护资源,客户端携带令牌访问资源服务,如果令牌合法则可成功访问资源服务中的资源,流程如下图:

上图的业务流程如下:

1、客户端请求认证服务申请令牌

2、认证服务生成令牌认证服务采用非对称加密算法,使用私钥生成令牌。

3、客户端携带令牌访问资源服务客户端在 Http header 中添加: Authorization:Bearer 令牌

注意这里的Authorization字段的值为 Bearer + 空格 + 令牌

4、资源服务请求认证服务校验令牌的有效性资源服务接收到令牌,使用公钥校验令牌的合法性。

5、令牌有效,资源服务向客户端响应资源信息

2)授权配置

基本上所有微服务都是资源服务,这里我们在 课程管理服务 上配置授权控制,当配置了授权控制后如要访问课程信息则必须提供令牌。

在我们导入的 auth 工程的 resources 下可以看到一个 xc.keystore 文件,该文件是用于认证的一个私钥文件,用于生成我们的授权码,生成的授权码可以使用 公钥 文件来进行校验。下面我们来做一个简单的实验来了解整个校验的流程。

1、配置公钥

认证服务生成令牌采用非对称加密算法,认证服务采用私钥加密生成令牌,对外向资源服务提供公钥,资源服务使
用公钥 来校验令牌的合法性。

day16资料 下的公钥拷贝到 publickey.txt 文件中,将此文件拷贝到资源服务工程的 classpath

2、添加依赖

<!--oatuh2-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

4、在 config 包下创建 ResourceServerConfig 类:

package com.xuecheng.manage_course.config;

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的PreAuthorize注解
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
   
  //公钥
  private static final String PUBLIC_KEY = "publickey.txt";
  //定义JwtTokenStore,使用jwt令牌
  @Bean
  public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
   
    return new JwtTokenStore(jwtAccessTokenConverter);
  }
  //定义JJwtAccessTokenConverter,使用jwt令牌
  @Bean
  public JwtAccessTokenConverter jwtAccessTokenConverter() {
   
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setVerifierKey(getPubKey());
    return converter;
  }
    /**
      * 获取非对称加密公钥 Key
      * @return 公钥 Key
      */
  private String getPubKey() {
   
    Resource resource = new ClassPathResource(PUBLIC_KEY);
    try {
   
      InputStreamReader inputStreamReader = new
          InputStreamReader(resource.getInputStream());
      BufferedReader br = new BufferedReader(inputStreamReader);
      return br.lines().collect(Collectors.joining("\n"));
    } catch (IOException ioe) {
   
      return null;
    }
  }
  //Http安全配置,对每个到达系统的http请求链接进行校验
  @Override
  public void configure(HttpSecurity http) throws Exception {
   
    //所有请求必须认证通过
    http.authorizeRequests().anyRequest().authenticated();
  }
}

3)授权测试

这里我们使用 POSTMAN 测试课程图片查询

GET http://localhost:31200/course/coursepic/list/4028e58161bd3b380161bd3bcd2f0000

请求时没有携带令牌则报错:

{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}

请求时携带令牌:

http header 中添加 Authorization: Bearer 令牌

当输入错误的令牌也无法正常访问资源。

4)解决swagger-ui无法访问

这个问题可以单独提取出来,发布到csdn上。

当课程管理加了授权之后再访问 swagger-ui 则报错

修改授权配置类 ResourceServerConfigconfigure 方法:

针对 swagger-ui 的请求路径进行放行:

//Http安全配置,对每个到达系统的http请求链接进行校验
@Override
public void configure(HttpSecurity http) throws Exception {
   
    //所有请求必须认证通过
    http.authorizeRequests()
            //下边的路径放行
            .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui",
                    "/swagger-resources","/swagger-resources/configuration/security",
                    "/swagger-ui.html"
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值