Oath2.0 cookbook--使用Spring Security保护您的Web应用程序

前言

OAuth 2.0是用于授权的标准协议,它专注于简化客户端开发人员的工作,同时为Web应用程序,桌面应用程序,移动电话等提供特定的授权流程。 给定OAuth规范可用的文档,您可能会认为它很复杂。 但是,本书承诺通过简单食谱中的示例来帮助您开始使用OAuth 2.0。 它着重于通过有趣的配方为各种应用程序提供特定的授权流。 它还提供了有用的食谱,可用于使用Spring Security解决实际问题并创建Android应用程序

本书涵盖的内容

第1章,OAuth 2.0基础,包含一些食谱,这些食谱将通过简单的食谱涵盖OAuth 2.0的基础知识,这些简单的食谱使读者可以与受OAuth 2.0保护的公共API(例如Facebook,LinkedIn和Google)进行交互。

第2章,实现自己的OAuth 2.0提供程序,介绍了实现自己的OAuth 2.0提供程序的方式,并介绍了考虑不同OAuth 2.0授予类型的有助于Authorization Server和Resource Server配置的方法。 它还介绍了如何使用不同的数据库存储访问令牌来有效地使用刷新令牌。

第3章,使用OAuth 2.0受保护的API,介绍了有助于创建OAuth 2.0客户端应用程序的配方,这些应用程序可以与OAuth 2.0规范中描述的所有授权类型进行交互。 它还介绍了如何在客户端上管理刷新令牌。

第4章,OAuth 2.0配置文件,介绍了一些OAuth 2.0配置文件以及如何使用Spring Security OAuth2实现它们。 指定这些配置文件是为了帮助解决OAuth 2.0规范未涵盖的特定情况,例如令牌吊销和允许进行远程验证的令牌自省。 本食谱还提供了一些建议,例如使用远程验证时如何以及何时使用缓存。

第5章,使用JWT的自包含令牌,着重介绍如何将JWT用作OAuth 2.0访问令牌以及如何实现JWT的主要扩展,例如JWS和JWE,提供签名和加密以保护JWT访问令牌所传达的内容 。 本章还提供了一种很好的方法,可以通过在OAuth 2.0上使用占有权证明语义来提高应用程序的安全性。

第6章,用于身份验证的OpenID Connect,介绍了授权和身份验证之间的区别,以及OAuth 2.0如何帮助构建身份验证协议。 为了说明OpenID Connect的用法,本章介绍的所有配方均针对客户端应用程序,而不是构建OpenID Connect提供程序。

第7章,实现移动客户端,介绍了如何使用Android作为食谱的平台来实现OAuth 2.0本机移动客户端。 本章介绍了由最近发布的针对本机应用程序的名为OAuth 2.0的规范所指定的一些准则。

第8章,避免常见漏洞,涵盖了更好地保护OAuth 2.0生态系统中考虑的主要组件的方法。

第一章:OAuth 2.0基础

本章涵盖以下食谱:
准备环境
从客户端的Facebook中读取用户的联系人
在服务器端从Facebook读取用户的联系人
访问OAuth 2.0 LinkedIn受保护的资源
访问绑定到用户会话的OAuth 2.0 Google受保护的资源

介绍

本章的主要目的是帮助您与流行的Web应用程序和社交媒体集成,尽管同时使您熟悉OAuth 2.0规范的基本原理。

在深入探讨几个用例的食谱之前,让我们看一下将涵盖的大多数场景的概貌。 这将使您有机会回顾有关OAuth 2.0规范的一些重要概念,因此我们可以与整本书中使用的术语保持一致。

资源所有者->移动客户端--->身份提供者
| ---->资源服务器
| ----------------> oauth 2.0避免器--- |->授权服务器---->关系数据库redis
| |-> |->资源服务器
| |
| ---> Web客户端--->第三方应用程序

上图显示了OAuth 2.0规范的四个主要组成部分:

资源所有者
授权服务器
资源服务器
客户

仅为了查看这些组件的用途,请记住,资源所有者是委派第三方应用程序代表其使用资源的权限的用户。 提到的第三方应用程序由客户端代表,我将其描述为移动客户端和Web客户端。 用户的资源通常由资源服务器维护和保护,例如,资源服务器可以与授权服务器一起实现为单个组件。 授权服务器和资源服务器的组成被称为OAuth 2.0提供程序,以简化给予受OAuth 2.0保护的应用程序的术语。

准备环境


由于大多数示例都是用Java编写的,因此我们还将需要一个集成开发环境(IDE)和一个好的框架来帮助我们编写简单的Web应用程序(因为OAuth 2.0协议是为HTTP使用而设计的),它将是Spring。 为了简化与Spring相关的技术的使用,本食谱将帮助您使用Spring Boot准备应用程序,并提供示例端点以及如何使用Maven运行该项目。

做好准备


如前所述,我们将使用Spring Boot Framework运行大多数配方,从而简化了基于Spring Framework的应用程序的开发。 因此,要运行此食谱,您仅需要一个可以从Internet下载一些文件,在计算机上正确配置的Java 8以及CURL工具的环境。

CURL是允许您通过命令行运行HTTP请求的工具。 在Linux和Mac OS环境中,默认情况下它是可用的,因此,如果要在Windows上运行配方,则应首先安装它。 可以从https://curl.haxx.se/download.html下载该工具并进行安装,您只需解压缩并将二进制文件的路径添加到Windows的PATH环境变量即可。

怎么做:

以下步骤描述了如何准备环境,以及如何从Spring Initializr网站生成一个简单项目,该项目将使用适当的Maven命令执行:

通过访问 // https://start.spring.io/使用Spring Initializr服务生成一个项目。 Spring Initializr提供了许多选项来开始设置项目,例如,如果您想使用Maven或Gradle管理项目依赖项,要使用哪个版本的Spring Boot,要使用哪些依赖项,甚至将语言从Java更改为 Groovy或Kotlin。

对于此简单测试,只需使用Java语言和Spring Boot 1.5.7版的项目管理器Maven Project的默认值即可。

在“项目元数据”中,将“组”字段的值更改为com.packt.example。

仍在项目元数据上,将工件名称更改为simplemvc。

在“依赖关系”部分中,键入web,然后选择“使用Tomcat和Spring MVC进行全栈Web开发”。 选择正确的选项后,您将在“选择的依赖项”下面看到“ Web”标签,如下所示:

设置完此简单示例的所有要求之后,单击“生成项目”按钮,您的浏览器将开始将ZIP文件下载到您的“下载”文件夹中。

下载该文件后,您可以将其解压缩并将其导入到IDE中,以浏览所创建项目的结构。 对于Eclipse用户,只需将项目导入为Maven项目即可。

打开类SimplemvcApplication,您将在IDE中看到以下代码:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.wangjunji</groupId>
	<artifactId>auth20</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>auth20</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

代码

package com.wangjunji.auth20;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
@SpringBootApplication
public class Auth20Application {

	@GetMapping("/message")
	public ResponseEntity<String> getMessage(){
		return ResponseEntity.ok("hello");
	}
	public static void main(String[] args) {
		SpringApplication.run(Auth20Application.class, args);
	}

}

OAuth 2.0规范可通过RFC 6749获得,网址为:https:/​/​tools.​ietf.org/​html/​rfc6749
可以在下面阅读有关Spring Boot的更多信息:https:/​/​docs.​spring.​io/​spring-​boot/docs/​current/​reference/​htmlsingle
这个怎么运作...
由于使用了Spring Boot,我们可以利用Spring MVC和Spring Security等项目。 这些Spring项目可帮助我们编写Web应用程序,REST API,并帮助我们保护应用程序的安全。 例如,通过使用Spring Security OAuth2项目,我们可以另外配置自己的OAuth 2.0提供程序,使其像客户端一样工作。 这很重要,因为尝试编写自己的OAuth Provider的人将不得不处理太多细节,这很容易导致OAuth Provider不安全。 Spring Security OAuth2已经解决了任何开发人员都必须考虑的主要问题。

另外,Spring Boot简化了应用程序引导的初始步骤。 当创建没有Spring Boot的Spring项目时,我们需要通过照顾可能的库冲突来手动处理依赖项。 为了解决这个问题,Spring Boot提供了一些由启动程序提供的预配置模块。 作为一个有用的入门示例,让我们考虑一个带有Spring Data JPA的应用程序。 只需声明spring-boot -starterdata-jpa即可自动导入所有依赖项,而不是声明hibernate,entity-manager, and transaction-api的所有依赖项。

开始使用Spring Boot时,通过使用Pivotal提供的Spring Initializr服务(现在是Spring维护者),事情会变得更加容易。

还有更多...
可以用任何Java IDE导入和执行用Java呈现的所有示例,但是我们将使用Eclipse,因为它是世界各地的开发人员认可的大型工具。 尽管本书介绍了使用Eclipse的方法,但如果需要,您也可以坚持使用首选工具。 如今,许多项目都是使用Gradle设计的,但是许多开发人员仍然习惯于使用Maven创建项目以管理依赖关系和项目本身。 因此,为避免IDE插件出现技巧错误或任何其他类型的问题,使用Spring Boot的配方将由Maven管理。 另外,Eclipse IDE已经附带了一个Maven插件,在编写本书时,它不适用于Gradle。 要在Eclipse中使用Gradle运行项目,必须安装特定的插件。

也可以看看
Spring Boot提供了许多入门工具,可以帮助您使用大量工具和库来开发应用程序。 如果您想搜索更多,请转到http:/​/​docs.​spring.​io/spring-​boot/​docs/​1.​5.​7.​RELEASE/​reference/​htmlsingle/​#using-​boot-​starter

从客户端的Facebook中读取用户的联系人

本食谱将向您介绍如何使用隐式授予类型与Facebook集成,这对于公共客户端来说是更好的选择,并且可以直接在用户的Web浏览器上运行。

您可能已经知道,授予类型为应用程序定义了不同的方法来从授权服务器检索访问令牌。 授权类型可以适用于与正在开发的客户端类型有关的给定方案。 提醒一下,OAuth 2.0规范定义了两种类型的客户端类型:公共和机密.

做好准备
要运行此食谱,您必须使用Spring Boot创建一个Web应用程序,这将有助于应用程序的开发。 此外,我们还需要在Facebook上注册我们的应用程序。 这是使用OAuth 2.0的重要一步,因为作为OAuth提供者,
Facebook需要知道哪些客户端正在请求访问令牌,并且资源所有者(用户)当然想知道要授予谁访问其个人资料的权限

怎么做...
请按照以下步骤创建一个客户端应用程序,以使用OAuth 2.0中的客户端流程与Facebook集成:

首先,请记住您必须拥有一个Facebook帐户,并且必须注册一个新的应用程序。 转到https://developers.facebook.com/apps/,您应该看到类似以下内容:

单击“创建新应用”以开始注册您的应用,然后您将看到以下界面,可用于定义应用的名称:

单击创建应用程序ID,您将被重定向到新创建的应用程序的仪表板,如下所示:

要开始使用Facebook的Graph API并检索用户的联系人,我们首先需要从Facebook提供的多种产品中选择一种产品。 对于我们现在需要的,您必须在Facebook登录框中单击“设置”按钮。

单击“设置”后,您必须选择一个平台,该平台必须为Web。

选择Web平台后,输入您的应用程序的站点URL。 我正在使用一个名为http://clientimplicit.test

保存网站的网址后,只需点击继续

现在,您可以通过单击左侧面板中的“设置”来设置应用程序的重定向URI,如下所示。 由于该应用程序尚未投入生产,因此我将重定向URI设置为http:// localhost:8080 / callback。 不要忘记保存更改:

现在,您可以单击面板左侧的仪表板,以便获取App ID和App Secret,它们分别对应于OAuth 2.0规范的client_id和client_secret。

从仪表板复制App ID和App Secret,如以下屏幕快照所示,如下所示,因此我们可以在后续步骤中使用以下代码:

一旦我们在Facebook上注册了客户,我们就可以开始编写代码以使用隐式授予类型检索OAuth 2.0访问令牌(从客户端请求访问令牌)。

使用Spring Initializr在以下位置创建一个新的Web应用程序https://start.spring.io/并定义以下数据:
  将组设置为com.packt.example
将工件定义为客户端隐式
将Web和Thymeleaf添加为该项目的依赖项

在src / main / resources项目目录内的文件夹模板中创建文件client.html

增加内容client.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:charset="UTF-8">
<head>
    <meta charset="UTF-8">
    <title>CLIENT</title>
</head>
<body>
Press the following button to start the implicit flow.
<button id="authorize" type="button">Authorize</button>
<div id="box"></div>
</body>
</html>

我们添加到client.html页面的按钮没有任何行为。 因此,要允许用户启动隐式授予类型流程,请在body标签之后添加以下JavaScript代码:

在启动应用程序之前,我们需要映射一个URL模式,以便可以呈现之前编写的HTML代码。 为此,请打开类ClientImplicitApplication.java并确保您的代码如下所示:


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
@SpringBootApplication
public class ClientApplication {
	@GetMapping("/")
	public String client(){
		return "client";
	}

	public static void main(String[] args) {
		SpringApplication.run(ClientApplication.class, args);
	}

}

在前面的代码中,我们已将应用程序的根目录映射到client.html网页。 但是,现在所有这些都是为了向用户发送授权服务器(在本例中为Facebook),以便她可以向我们的应用程序授予对受保护资源(她的朋友)的访问权限。 尝试启动该应用程序,然后转到http:// localhost:8080 /

单击client.html将提供的; Authorize按钮以启动Implicit授予流程,使用您的Facebook帐户登录,并接受客户端隐式应用程序所请求的权限(确保在客户端中正确声明了jquery.html文件)。

如果您在同意用户页面上授予所有权限,则应将您重定向到在Facebook的客户端注册阶段指定的http:// localhost:8080 / callback URL。 单击继续,并注意收到的内容和浏览器地址栏中的URL片段。 它应该类似于以下内容:

http://localhost:8080/callback#access_token=EAAbsiSHMZC60BANUwKBDCYeySZCjcBpvFuUO1gXsfTGwWjnZAFTAZBIJB62jdUroAcNuZAVWO24yeqo0iazWYytVgrQ1bgNWI8vm07Ws4ZCHXpGridHfZB6PQ1rzM4BzP29IljgTTuBLZBFQBEnEn2LJiOWJjA8J6Y73BLcjIe2vVMZB9c2GnZBpiK4iZAWEtkTsMEZD&expires_in=7152

现在,我们需要提取#character之后的access_token和expires_in参数,并开始使用Facebook Graph API来检索用户的朋友。

我们要做的第一件事是通过我们的默认控制器ClientImplicitApplication创建另一个URL映射。 打开此类并添加以下方法,以便我们处理Facebook的重定向:

@GetMapping("/callback")
public String callback() { return "callback_page"; }

如我们所见,回调方法返回的是callback_page字符串,该字符串将自动映射到文件callback_page.html。 因此,让我们在src / main / resources项目目录中的templates文件夹内创建此文件。 首先,只需将以下HTML内容添加到callback_page.html文件中:

<!DOCTYPE html>
<html>
<head><title>Insert title here</title></head>
<body>
Friends who has also granted client-implicit
<div id="friends">
<ul></ul>
</div>
</body>
</html>

在收到acces_token作为URL片段之后,该文件将使用JavaScript代码与Facebook的graph API交互以检索用户的朋友,并将在<li>标签中接收的每个朋友填充标签<ul>。 让我们开始编写JavaScript代码,方法是在body标签之后添加以下内容

<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.
js"></script>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function() {
var fragment = window.location.hash;
});
/*]]>*/
</script>

由于片段变量中包含片段内容,因此在JavaScript代码末尾添加以下函数:

function getResponse(fragment) {
var attributes = fragment.slice(1).split('&');
var response = {};
$(attributes).each(function(idx, attr) {
var keyValue = attr.split('=');
response[keyValue[0]] = keyValue[1];
});
response.hasError = function() {
return !response['access_token'];
};
return response;
}

前面提供的代码创建了一个名为response的对象,该对象可能包含一个access_token或错误描述。 不幸的是,Facebook返回所有错误数据作为URL查询参数,而不是按照OAuth 2.0的规范使用片段。 至少由getResponse函数返回的对象可以判断响应是否有错误。

现在,将主要的JavaScript代码更新为以下内容。 以下代码从URL片段中提取响应,作为安全措施清除URL的片段,如果发生错误,仅通过<div> HTML标记向用户显示一条消息:

发布了158 篇原创文章 · 获赞 28 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/wangjunji34478/article/details/105613733