https://www.jianshu.com/p/ded9dc32f550

2024-01-05 22:59

本文主要是介绍https://www.jianshu.com/p/ded9dc32f550,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://www.jianshu.com/p/ded9dc32f550

第十八章:SpringBoot项目中使用SpringSecurity整合OAuth2设计项目API安全接口服务

96 恒宇少年 关注

 1.1 2017.04.22 17:52* 字数 3585 阅读 29190评论 55喜欢 118赞赏 1

OAuth是一个关于授权的开放网络标准,在全世界得到的广泛的应用,目前是2.0的版本。OAuth2在“客户端”与“服务提供商”之间,设置了一个授权层(authorization layer)。“客户端”不能直接登录“服务提供商”,只能登录授权层,以此将用户与客户端分离。“客户端”登录需要OAuth提供的令牌,否则将提示认证失败而导致客户端无法访问服务。下面我们就来讲解下SpringBoot项目中是如何配置使用OAuth2服务器端,并让OAuth2整合SpringSecurity来保护我们的REST接口。

本章目标

基于SpringBoot项目提供一个继承OAuth2安全框架的REST API服务端,必须获取访问授权令牌后才可以访问资源。

OAuth2授权方式

我们在文章开始已经说过了,我们的保护资源必须通过授权得到的令牌才可以访问。那么我们这个授权令牌要通过什么方式获取呢?

OAuth2为我们提供了四种授权方式:

1、授权码模式(authorization code)
2、简化模式(implicit)
3、密码模式(resource owner password credentials)
4、客户端模式(client credentials)

授权码模式

授权码相对其他三种来说是功能比较完整、流程最安全严谨的授权方式,通过客户端的后台服务器与服务提供商的认证服务器交互来完成。流程如下图2所示:

图2

简化模式

这种模式不通过服务器端程序来完成,直接由浏览器发送请求获取令牌,令牌是完全暴露在浏览器中的,这种模式极力不推崇。流程如下图3所示:

图3

密码模式

密码模式也是比较常用到的一种,客户端向授权服务器提供用户名、密码然后得到授权令牌。这种模式不过有种弊端,我们的客户端需要存储用户输入的密码,但是对于用户来说信任度不高的平台是不可能让他们输入密码的。流程如下图4所示:

图4

客户端模式

客户端模式是客户端以自己的名义去授权服务器申请授权令牌,并不是完全意义上的授权。如下图5所示:

图5

上述简单的介绍了OAuth2内部的四种授权方式,我们下面使用密码模式来进行测试,并且我们使用数据库中的用户数据来做验证处理,下面我们先来构建项目。

构建项目

我们使用IndeiiJ IDEA工具来构建一个SpringBoot项目,目前最新版本的是1.5.3,应该是昨天刚正式发布。项目我们预先引入几个模块,Web、JPA、MySQL、Security、SpringSecurityOAuth2、Druid等,项目结构如下图6所示:

图6

项目构建完成后我们要配置数据库表结构,因为我们要是数据库内保存AccessToken以及RefershToken还有我们的SpringSecurity用户验证信息以及用户角色信息等。

配置数据库

安全用户信息表

用户信息表包含了简单的登录名、密码、邮箱、状态等。表结构如下图7所示:

图7

安全角色信息表

角色信息表结构如下图8所示:

图8

用户角色关联表

用户与角色关联表结构如下图9所示:

图9

AccessToken信息表

我们使用的是SpringSecurityOAuth2提供的Jdbc方式进行操作Token,所以需要根据标准创建对应的表结构,access_token信息表结构如下图10所示:

图10

RefreshToken信息表

刷新Token时需要用到refresh_token信息表结构如下图11所示:

图11

我们的数据库表结构已经建完了,下面我们只需要创建用户信息、角色信息的实体即可,因为OAuth2内部操作数据库使用的JdbcTemplate我们只需要传入一个DataSource对象就可以了,实体并不需要配置。

创建用户实体

用户实体如下图12所示:

图12

创建角色实体

角色实体如下图13所示:

图13

用户实体以及角色实体是用来配置SpringSecurity时用到的实体,我们配置SpringSecurity时需要使用SpringDataJPA从数据库中读取数据,下我们来配置UserJPA以及AuthorityJPA。

UserJPA

配置访问数据库获取用户信息,代码如下图14所示:

图14

我们在UserJPA内添加了一个自定义查询,使用了HQL语法来构建的语句,根据用户名不区分大小写进行查询。

Application.yml配置文件

我们从之前的项目中第十三章:SpringBoot实战SpringDataJPA中源码复制一个application.yml配置文件到项目resources下(注意:需要修改对应的数据库配置),如下图所示:

.

AuthorityJPA

配置访问数据库中的角色列表,代码如下图15所示:

图15

下面我们来配置两个控制器用来区分我们配置OAuth2是否已经生效。

HelloWorldController

我在HelloWorldController内只添加一个字符串的输出,这个控制器我们开放,让SpringSecurity不去管理,配置将会在下面展现,控制器代码如下图16所示:

图16

SecureController

这个控制器是需要我们获取授权Token后使用Token才可以访问到的,代码如下图17所示:

图17

综上所述我们的项目基础的构建已经完成,大家都知道SpringSecurity在使用数据库的数据时需要自定义UserDetailsService用来从数据库中根据用户名查询用户信息以及角色信息并返回给SpringSecurity存放到内存中。

自定义UserDetailsService

我们创建一个名叫HengYuUserDetailsService的类并且实现UserDetailsService接口,代码如下图18所示:

图18

我们在HengYuUserDetailsService类中做了从数据库读取用户的操作,如果没有查询到用户直接抛出异常提示,如果查询到并且设置对应的角色后返回SpringSecurity内置的User对象实例。

开启SpringSecurity配置

下面我们来配置SpringSecurity相关的内容,我们新创建一个配置类SecurityConfiguration,代码如下图19所示:

图19

我们在配置类中注入了上面我们自定义的HengYuUserDetailsService以及用户密码验证规则,我们使用ignoring()方法排除了HelloWorldController内的公开方法,这里可以配置通配符的形式排除。

配置安全资源服务器

下面我们开始配置相关OAuth2的内容,我们创建一个OAuth2总配置类OAuth2Configuration,类内添加一个子类用于配置资源服务器,如下图20所示:

图20

我们在OAuth2Configuration配置类中添加子类ResourceServerConfiguration继承自ResourceServerConfigurerAdapter完成资源服务器的配置,使用@EnableResourceServer注解来开启资源服务器,因为整合SpringSecurity的缘故,我们需要配置登出时清空对应的access_token控制以及自定义401错误内容(authenticationEntryPoint),在配置类中我们排除了对/hello公开地址拦截以及/secure下的所有地址都必须授权才可以访问。

自定义401错误码内容

我们上图已经用到了对应的类CustomAuthenticationEntryPoint,该类是用来配置如果没有权限访问接口时我们返回的错误码以及错误内容,代码如下图21所示:

图21

定义登出控制

当我们退出系统时需要访问SpringSecrutiy的logout方法来清空对应的session信息,那我们退出后改用户的access_token还依然存在那就危险了,一旦别人知道该token就可以使用之前登录用户的权限来操作业务。logout控制代码如下图22所示:

图22

开启OAuth2验证服务器

我们还是在OAuth2Configuration配置类中添加一个子类,用于开启OAuth2的验证服务器,代码如下图23、24所示:

图23

图23中我们创建了一个名叫AuthorizationServerConfiguration的类继承自AuthorizationServerConfigurerAdapter并且实现了EnvironmentAware(读取properties文件需要)接口,并使用@EnableAuthorizationServer注解开启了验证服务器,可以看到我们使用SpringSecurityOAuth2内定义的JdbcStore来操作数据库中的Token,当然需要有需要我们可以通过SpringDataJPA自定义Sotre

图24

图24中我们的OAuth2的客户端配置并没有从数据库中读取而是使用了内存中获取,因为本章的内容比较多,所以在后期文章中我们会再次讲到如何从数据库中获取clients进行验证。我们在创建客户端信息时使用到了application.properties配置文件的自定义配置,具体配置内容如下图25所示:

图25

运行测试

项目编写完成,接下来我们使用SpringBootApplication形式来运行项目进行测试,运行项目时查询控制台输出日志是否正确!

我们先来使用Postman工具访问一下我们公开的地址127.0.0.1:8080/hello,如下图26所示:

图26

可以看到我们是可以正确的访问到接口输出内容的,下面我们再来访问一下被oauth2管理的地址127.0.0.1:8080/secure,如下图27所示:

图27

我们可以看到直接给我们返回了一个页面,这样就不对了,我们应该得到一个401的错误码以及自定义的信息才对,当然我们需要添加一些配置来完成这个功能,我们打开application.properties配置文件添加如下图28配置:

图28

图中画红色框的就是我们新添加的配置内容,这个配置的意思时,将我们的资源拦截的过滤器运行顺序放到第3个执行,也就是在oauth2的认证服务器后面执行,我们重启下项目再来访问下刚才的地址,输出内容如下图29所示:

图29

可以看到正如我们预期一样,返回了401错误以及我们自定义的错误码”Access Denied“,下面我们来获取access_token。

获取AccessToken

我们在获取token之前需要在数据库中添加几条对应的数据,具体的SQL我会放到源码项目的resources目录下,文章地址有源码地址。我们来访问/oauth/token地址获取access_token,如下图30所示:

图30

可以看到我们访问的地址,grant_type使用到了password模式,我们在上面的配置中就是配置我们的客户端(yuqiyu_home_pc)可以执行的模式有两种:password、refresh_token。获取access_token需要添加客户端的授权信息clientid、secret,通过Postman工具的头授权信息即可输出对应的值就可以完成Basic Auth的加密串生成。

成功访问后oauth2给我们返回了几个参数:

access_token:本地访问获取到的access_token,会自动写入到数据库中。
token_type:获取到的access_token的授权方式
refersh_token:刷新token时所用到的授权token
expires_in:有效期(从获取开始计时,值秒后过期)
scope:客户端的接口操作权限(read:读,write:写)

使用AccessToken访问

我们使用获取到的access_token值来访问对应的地址http://127.0.0.1:8080/secure?access_token=9ca7fd9b-1289-440b-b1a1-0303782f660e,效果如下图31所示:

图31

可以看到我们已经可以正常的访问到数据内容了,证明我们的access_token是有效的。当我们用到的token已经过期时效果如下图32所示:

图32

oauth2告诉我们需要刷新Token了,您传入的token值已经过期了。

刷新AccessToken

我们的access_token过期我们需要刷新后返回新的token,使用新token才能继续操作数据接口。刷新access_token如下图33所示:

图33

看到上图33红色框内的值了吗?这个就是我们之前获取token时,oauth2给我们返回的refresh_token值,我们需要用到该值来进行刷新token。新的token值得有效期可以看到又是我们配置的默认1800秒,刷新token时oauth2还是给我们返回了一个refersh_token值,该值要作为下次刷新token时使用。

总结

综上内容就是本章的全部内容,本章的内容比较多希望读者可以仔细阅读,本章主要讲解了SpringBoot作为框架基础上配置SpringSecurity安全框架整合OAuth2安全框架做双重安全,讲解如果通过数据库的形式获取到授权用户信息以及角色列表,通过内存配置的OAuth2的客户端配置来获取access_token以及如何使用access_token访问受保护的资源接口。

本章代码已经上到码云:

SpringBoot配套源码地址:https://gitee.com/hengboy/spring-boot-chapter

SpringCloud配套源码地址:https://gitee.com/hengboy/spring-cloud-chapter

SpringBoot相关系列文章请访问:目录:SpringBoot学习目录

QueryDSL相关系列文章请访问:QueryDSL通用查询框架学习目录

SpringDataJPA相关系列文章请访问:目录:SpringDataJPA学习目录

SpringBoot相关文章请访问:目录:SpringBoot学习目录,感谢阅读!

欢迎微信扫码加入知识星球,恒宇少年带你走以后的技术道路!!!

知识星球 - 恒宇少年

这篇关于https://www.jianshu.com/p/ded9dc32f550的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/574429

相关文章

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“

3.比 HTTP 更安全的 HTTPS(工作原理理解、非对称加密理解、证书理解)

所谓的协议 协议只是一种规则,你不按规则来就无法和目标方进行你的工作 协议说白了只是人定的规则,任何人都可以定协议 我们不需要太了解细节,这些制定和完善协议的人去做的,我们只需要知道协议的一个大概 HTTPS 协议 1、概述 HTTPS(Hypertext Transfer Protocol Secure)是一种安全的超文本传输协议,主要用于在客户端和服务器之间安全地传输数据

com.google.gson.JsonSyntaxException:java.lang.IllegalStateException异常

用Gson解析json数据的时候,遇到一个异常,如下图: 这个异常很简单,就是你的封装json数据的javabean没有写对,你仔细查看一下javabean就可以了 比如:我的解析的代码是             Gson gson = new Gson();             ForgetJson rb = gson.fromJson(agResult.mstrJson, For

The import com.google cannot be resolved

The import com.google cannot be resolved,报错: 第一感觉就是缺少jar包,因为项目用maven管理,所以在pom.xml中添加: <dependency>  <groupId>com.google.code.gson</groupId>  <artifactId>gson</artifactId>  <version>2.3.1</ver

HTTP协议 HTTPS协议 MQTT协议介绍

目录 一.HTTP协议 1. HTTP 协议介绍 基本介绍: 协议:  注意: 2. HTTP 协议的工作过程 基础术语: 客户端: 主动发起网络请求的一端 服务器: 被动接收网络请求的一端 请求: 客户端给服务器发送的数据 响应: 服务器给客户端返回的数据 HTTP 协议的重要特点: 一发一收,一问一答 注意: 网络编程中,除了一发一收之外,还有其它的模式 二.HTT

Docker容器创建时,无法访问镜像源:Could not connect to archive.ubuntu.com:80

1.问题描述 当基于dockerfile创建容器时,遇到Could not connect to ...、Failed to fetch ...等异常时,大概原因是没有配置好容器创建所需的镜像源。这里以Ubuntu基础镜像源为例。 dockerfile内容 FROM ubuntuRUN apt update && apt install python3 -y && apt install

Springboot工程配置https访问

背景 因为前端工程使用nginx配置了https访问,在https直接请求我们Springboot后端的http接口会报错。那么我们就需要配置使得我们后端的springboot服务支持https访问。 证书生成 在配置springboot工程https之前,我们需要生成自签名证书以及Spring Boot通常使用的PKCS#12格式的密钥库。 生成自签名证书 openssl req -x

两步搞定 Tomcat 下启用 https:// 访问

这个简单教程中我们通过简单的两步就可以在 Tomcat 7 中启用 HTTPS 访问。 第一步:创建 .keystore 文件 使用如下命令生成 .keystore 文件 windows : 1 %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA Linux: 1 $JAVA_HOM

ngrok | 内网穿透,支持 HTTPS、国内访问、静态域名

前言 当我们需要把本地开发的应用展示给外部用户时,常常会因为无法直接访问而陷入困境。 就为了展示一下,买服务、域名,搭环境,费钱又费事。 那有没有办法,让客户直接访问自己本机开发的应用呢? 这种需求场景这么多,当然有现成的技术 —— 内网穿透。 什么是内网穿透? 内网穿透是一种网络技术,它允许外部互联网用户访问部署在本地网络(内网)中的服务或设备。 通常,家庭或企业网络都位于内网,连