朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。
在Java世界中,有两个主要的构建系统:Gradle和Maven。 构建系统主要管理潜在的复杂依赖关系网并编译项目。 还将已编译的项目以及所有资源和元文件打包到最终的.war
或.jar
文件中。 对于简单的构建,Maven和Gradle之间的选择几乎是个人喜好之一,或者也许是您的CTO或技术经理的喜好。 他们俩都很棒。 但是,对于更复杂的项目,Gradle是赢家。
使用Gradle构建的利与弊
我个人喜欢Gradle; 我讨厌XML,并花了几年时间从事大型,复杂的Java / Groovy项目,如果没有Gradle,这是不可能的。 除了缺少XML以外,Gradle还使用Groovy或Kotlin编写的构建文件提供了灵活性和构建速度。 借助Kotlin或Groovy的全部功能以及Gradle API库,您可以创建功能强大且复杂的构建脚本。 这肯定是一种祝福和诅咒。
DSL(特定于域的语言)需要一些时间来适应,并且Gradle以难以学习而著称。 但是,我认为这主要是因为人们已经习惯了Maven。 使用Gradle,您实质上可以学习一种构建语言 ,而不只是简单地学习XML。 与仅在Maven中添加依赖项相比,充分利用Gradle无疑具有更高的学习曲线。 但是向Gradle文件添加依赖项实际上并不比在Maven中困难。 扩展和自定义Gradle构建比编写Maven插件和自定义构建步骤要简单得多。
Gradle还极大地缩短了构建时间,尤其是在大型项目中,因为Gradle仅处理已更改的任务和文件就可以很好地完成工作。 此外,它提供了构建缓存和构建守护程序,使重复构建的性能更高。 而且,像Maven一样,它使用并行线程进行依赖关系解析和项目构建。 同样,对于小型,简单的构建,这种性能提升可能并不明显。 但是对于较大的项目,这是巨大的。
因此,总结一下。 摇篮是:
- 大型项目更快
- 无限可定制==更陡峭的学习曲线
- 使用Groovy或Kotlin代替XML
而Maven是:
- 尝试和真实
- 无处不在
- 对于不需要自定义的较小项目更简单
- 带有XML和尖括号
Groovy的优点
简要介绍一下Groovy。 Groovy是一种JVM语言,它可以编译为与Java相同的字节码,并且可以与Java类无缝地互操作。 Groovy是Java的向后兼容超集,这意味着Groovy可以透明地与Java库和代码交互。 但是,它还增加了许多新功能:可选的键入,函数式编程,运行时灵活性以及许多元编程内容。 它还极大地清理了Java中许多冗长的仪式代码。 Groovy尚未成为主流的开发语言,在很大程度上被Scala和Kotlin所取代,但是它已经在测试(由于其简化的语法和元编程功能)和构建系统中占据了一席之地。
依存关系
您需要为本教程安装一些内容(以及注册Okta帐户):
Java:您可能已经安装了Java。 本教程至少需要Java 1.8。 如果不是,请导航到OpenJDK网站并安装它。 您还可以在OSX和Linux上使用Homebrew安装Java,方法是: brew cask install java
。
Gradle:通常使用Gradle构建,实际上并不需要安装它。 Gradle提供了一个称为Gradle包装器的功能,该功能包括一个脚本,该脚本可下载正确的Gradle版本以自动构建项目。 但是,由于本教程是有关Gradle的教程,因此在本教程中,您可以继续进行安装。 纯娱乐。 Gradle可以使用自制软件, SDKMAN或通过下载进行安装。 他们在Gradle网站上有说明 。
Okta开发者帐户 :对于示例应用程序的身份验证部分,您将需要一个免费的Okta开发者帐户。 您将使用Okta作为OAuth / OIDC(OpenID Connect)提供商。 如果您还没有,请转到Okta注册页面并注册。 注意:首次登录时,您需要单击Admin按钮以进入开发人员控制台。
HTTPie :您将使用一个很棒的命令行实用程序来从命令行运行一些HTTP请求。 如果尚未安装,请访问他们的网站并安装。
下载样例项目
出于本教程的目的,我编写了一个简单的示例项目。 这是使用Spring Boot和Java编写的基本REST服务。 Spring Boot使构建安全的Java Web应用程序变得容易。 另外,我还包括使用OAuth 2.0 / OIDC(OpenID Connect)的JWT身份验证。 该项目使用的身份验证提供程序是Okta,即软件即服务身份管理提供程序。 您应该已经注册了免费的开发者帐户 。
请继续从GitHub页面下载或克隆示例项目,并检出start
分支。
git clone https://github.com/oktadeveloper/okta-spring-boot-gradle-example.git -b start
cd reponame
了解
build.gradle
文件是Gradle项目的核心。 在此配置构建。 这相当于Maven的pom.xml
(没有所有令人讨厌的尖括号–我是否提到我作为一个年轻的开发人员受到XML的攻击,并且从未克服过?)
让我们来看一个。 这来自刚刚下载的示例项目。
// 1) configure the requirements to run the build script
buildscript {
// set a custom property
ext {
springBootVersion = '2.1.6.RELEASE'
}
// check for dependencies in Maven Central when resolving the
// dependencies in the buildscript block
repositories {
mavenCentral()
}
// we need the spring boot plugin to run the build script
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
// 2) apply some plugins
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
// 3) set some standard properties
group = 'com.okta.springboottokenauth'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
// 4) repos to search to resolve dependencies for the project
repositories {
mavenCentral()
}
// 5) project dependencies
dependencies {
implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' )
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.springframework.boot:spring-boot-starter-web')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation('org.springframework.security:spring-security-test')
}
理解Gradle构建文件的关键是要意识到它是一个脚本,内置在Groovy DSL中。 粗略地讲,它是一个配置脚本,它调用定义了配置选项的一系列闭包(请考虑函数,更多有关此内容)。 它几乎看起来像JSON或属性文件,尽管从技术上来说这是非常错误的,但是作为起点并不遥远。
但是,真正的强大之处在于build.gradle
是一个Groovy脚本。 因此,它可以执行任意代码并访问任何Java库,特定于构建的Gradle DSL和Gradle API。 您可能可以使用Gradle文件发射航天飞机。
Gradle
让我们从上至下查看脚本:
1) buildscript
闭包配置构建脚本本身(与应用程序相对)所需的属性,依赖项和源存储库。
2)接下来, apply plugin
,令人震惊地,应用插件。 这些扩展了Gradle-Groovy DSL框架的基本功能:应用了java
插件,以及Spring Boot和Spring依赖项管理。 Java插件将Gradle配置为期望标准Java项目目录结构: src/main/java
, src/main/resources
, src/test/java
等。可以将其配置为更改默认目录或添加新目录。 Gradle Java插件文档是细读更多信息的好地方。
3)接下来,将一些标准属性应用于构建。
4) repositories
块定义了构建脚本将在哪里寻找依赖项。 Maven Central是最常见的( mavenCentral()
),但是也可以配置其他存储库,包括自定义存储库和本地存储库。 可以使用mavenLocal()
将本地Maven缓存配置为存储库。 如果团队希望协调项目之间的构建,但又不想将项目构建文件实际捆绑在一起,这将很有帮助。
5)最后,定义项目依赖项。
标准的预定义闭包的顺序无关紧要,因为大多数build.gradle
文件仅定义依赖项,设置项目属性并使用预定义的任务,因此文件中元素的顺序无关紧要。 例如,没有理由将repositories
块放在dependencies
块之前。 您可以将build.gradle
文件看作只是Gradle在执行调用它的shell命令分配的任务之前读取的配置文件。
但是,当您开始使用Gradle的功能来定义自定义任务并执行任意代码时,它将变得更加复杂。 Gradle将以自上而下的方式读取build.gradle
文件,并执行在其中找到的所有代码块; 根据此代码的作用,它可以在脚本中创建强制排序。 此外,当您定义自定义任务和属性(在Gradle API中找不到)时,排序很重要,因为这些符号不会被预先定义,因此必须在构建脚本中定义它们才能使用它们。
什么是封闭?
回到Groovy刚问世时,函数式编程是相当小众的领域,将诸如闭包之类的东西带入JVM感觉很疯狂。 如今,它变得更加普遍:Javascript中的每个函数都是闭包。 一般来说,闭包是具有范围的一流函数。
这意味着两件事:
- 闭包是可以在运行时作为变量传递的函数
- 闭包保留对定义它们的变量范围的访问
Java版本的闭包称为lambda。 这些是在1.8版中引入Java的,顺便说一句,这并不是在Groovy获得最初的流行和函数式编程开始发展的同时发生的。
为了演示lambda,请看一下名为LambdaTest.java
的JUnit测试。
src/test/java/com/okta/springboottokenauth/LambdaTest.java
interface SimpleLambda {
public int sum(int x, int y);
}
public class LambdaTest {
// create a lambda function with an var
// encapsulated in its scope
public SimpleLambda getTheLambda(int offset) {
int scopedVar = offset;
return (int x, int y) -> x + y + scopedVar;
}
@Test
public void testClosure() {
// get and test a lambda/closure with offset = 1
SimpleLambda lambda1 = getTheLambda(1);
assertEquals(lambda1.sum(2,2), 5);
// get and test a lambda/closure with offset = 2
SimpleLambda lambda2 = getTheLambda(2);
assertEquals(lambda2.sum(2,2), 6);
}
}
这个示例有些人为,但是演示了lambda的两个基本属性。 在闭包或lambda函数中,实现是在getTheLambda(int offset)
方法中定义的。 创建lambda时,将offset变量封装在闭包范围中并返回。 该lambda被分配给变量。 可以重复调用它,并且它将引用相同的作用域。 此外, 可以使用封装在单独作用域中并分配给其他变量的新偏移量变量来创建新的lambda 。
来自强大的面向对象的背景,封闭最初感觉就像虫洞在严格的对象范围连续体上打Kong一样,奇怪地将对象的各个部分随时间和空间连接在一起。
Gradle只是关闭
采取build.gradle
文件的依赖项部分:
dependencies {
implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' )
implementation('org.springframework.boot:spring-boot-starter-security')
...
}
没有Groovy DSL速记,实际上是:
project.dependencies({
implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' )
implementation('org.springframework.boot:spring-boot-starter-security')
...
})
括号中的所有内容实际上都是传递给project.dependencies()
方法的闭包。 project
对象是Project
类的实例, Project
类是构建的主要API父类。
如您所见,这些函数将一系列依赖项作为字符串传递。 那么,为什么不使用更传统的静态数据结构(如JSON,属性或XML)呢? 由于这些重载函数也可以接受闭包代码块,因此可以进行深度自定义。
Gradle网站上Project类的文档中此块的定义:
dependencies
{}
配置此项目的依赖项。
该方法针对此项目的DependencyHandler
执行给定的关闭。DependencyHandler
作为闭包的委托传递给闭包。
我们不需要深入研究Groovy闭包,但是上面提到的委托对象是可分配的上下文对象。 它的用法就像绑定this
Javascript一样,但是在这里,委托是一个单独的,可分配的变量,它使实际的执行范围保持不变并可以访问。
探索Gradle依赖项配置
依赖关系块内部是一系列配置和名称。
dependencies {
configurationName dependencyNotation
}
我们的build.gradle
文件使用两种配置: implementation
和testImplementation
。
implementation()
定义了编译时所需的依赖项。 这种配置方法称为compile
。 testImplementation()
并定义了仅用于测试所需的依赖项(旧的testCompile
)。
您可能会看到的另一个依赖项配置是runtimeOnly
和testRuntimeOnly
。 这声明了运行时提供的不需要对其进行编译的依赖项。
定义依赖关系的方法比对本文的范围有用的方法更多。 几乎可以说任何东西都可以是依赖项:本地文件,jar目录,另一个Gradle项目等…,并且可以将依赖项配置为执行某些操作,例如排除某些子依赖项。
值得注意的是:Gradle和Maven不能以完全相同的方式解决依赖关系。 您可以在Maven项目和Gradle项目中拥有相同的依赖关系集,最终在一个问题而不是另一个问题中遇到依赖关系问题。
例如,假设我们想从Okta Spring Boot Starter中排除Log4j依赖关系,我们可以这样做:
dependencies {
implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' ) {
exclude group: 'org.apache.logging.log4j', module: 'log4j-api'
}
}
或者说我们想将libs
目录中的所有文件都包含为依赖项:
dependencies {
implementation fileTree('libs')
}
完整的符号记录在Gradency文档站点上的DependencyHandler和Java插件的Gradle文档中 。
包装Gradle版本
关于Gradle的一件很棒的事情是Gradle包装器。 Gradle命令行是gradle
。 但是,您会注意到在网上的很多地方,您都会看到./gradlew
或gradlew.bat
。 这些是调用包装程序的命令。
包装器允许项目捆绑在项目本身内部构建项目所需的Gradle版本。 这样可以确保对Gradle的更改不会中断构建,因为正确的版本也将始终可用。 它还可以确保即使没有安装Gradle的人也可以运行构建。
它将以下文件添加到您的项目:
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
gradlew
和gradlew.bat
分别是Linux / OSX和Window的执行脚本。 他们使用gradle/wrapper
子目录中捆绑的Gradle .jar
运行build.gradle
文件。
该项目使用Gradle 5.5版本包装,如果按照建议安装了Gradle,则可以顺利运行该项目。 但是,您可以使用包装器轻松完成整个教程。
任务,任务和更多任务
任务是Gradle的核心。 Java插件添加了许多任务,包括: clean
, compile
, test
, jar
和uploadArchives
。 Spring Boot插件添加了bootRun
任务,该任务运行Spring Boot应用程序。
通常,任务是这样运行的: gradle taskName otherTaskName
,或使用包装器: ./gradlew taskName otherTaskName
。
如果打开终端并cd
到示例项目的基本目录,则可以使用gradle tasks
列出build.gradle
文件定义的所有任务。 tasks
本身就是由基本Gradle API定义的任务。
> Task :tasks
------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------
Application tasks
-----------------
bootRun - Runs this project as a Spring Boot application.
Build tasks
-----------
assemble - Assembles the outputs of this project.
bootJar - Assembles an executable jar archive containing the main classes and their dependencies.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
jar - Assembles a jar archive containing the main classes.
testClasses - Assembles test classes.
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'SpringBootGradleProject'.
components - Displays the components produced by root project 'SpringBootGradleProject'. [incubating]
dependencies - Displays all dependencies declared in root project 'SpringBootGradleProject'.
dependencyInsight - Displays the insight into a specific dependency in root project 'SpringBootGradleProject'.
dependencyManagement - Displays the dependency management declared in root project 'SpringBootGradleProject'.
dependentComponents - Displays the dependent components of components in root project 'SpringBootGradleProject'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'SpringBootGradleProject'. [incubating]
projects - Displays the sub-projects of root project 'SpringBootGradleProject'.
properties - Displays the properties of root project 'SpringBootGradleProject'.
tasks - Displays the tasks runnable from root project 'SpringBootGradleProject'.
Verification tasks
------------------
check - Runs all checks.
test - Runs the unit tests.
...
我想指出dependencies
任务。 它将列出一棵树,其中包含项目所需的所有依赖关系(包括子依赖关系)。 尝试在项目根目录中运行gradle dependencies
。 您可以使用dependencyInsight
任务深入查看特定的子dependencyInsight
项。
故障排除的另一个有用的任务是properties
任务,该任务列出了在根项目对象实例上定义的所有属性。
当然,在开发Spring Boot项目时,十分之九,我使用的命令是: ./gradlew bootJar
。 这是Spring Boot Gradle插件添加的一项任务,该任务将项目及其依赖项打包在一个jar文件中。
创建自定义任务
打开build.gradle
文件,并在末尾添加以下内容:
println "1"
task howdy {
println "2"
doLast {
println "Howdy"
}
}
println "3"
这将演示有关Gradle脚本如何工作的一些信息。 使用以下命令运行它:
./gradlew howdy
您将看到(省略了一些多余的行):
> Configure project :
1
2
3
> Task :howdy
Howdy
在这里,“ Configure project
任务将生成并运行生成脚本。 当Gradle执行Configure project
任务时,它会执行以下操作:
- 它到达第一个
println
并打印“ 1” - 它找到一个
howdy
任务定义块,一个闭包并执行,并显示“ 2”。 请注意,它不会执行doLast
闭包,因此尚未打印“ A”。 - 它继续执行脚本,并打到第四个
println
,并打印“ 3”。
至此,构建脚本本身已完成对构建环境的配置。 下一步是执行命令行上指定的所有任务,在本例中为howdy
任务。
这是task.doLast {}
块的执行位置,因此您会在输出中看到“ Howdy”。
doLast
是该块的误称;它的真正含义是类似于“任务操作”,而外部块是任务设置和配置。 见下文。
task howdy {
// always executed at during initial build script configuration
doLast {
// only executed if task itself is invoked
}
// always executed at during initial build script configuration
}
使用Graovy DSL根据Gradle文档定义任务的各种方法如下:
task taskName
task taskName { configure closure }
task taskName(type: SomeType)
task taskName(type: SomeType) { configure closure }
只是为了doLast
,在运行构建脚本时立即执行 “配置闭包”,而在专门执行任务时执行在配置闭包中定义的doLast
闭包。
将第二个自定义任务添加到build.gradle
文件:
task partner {
println "4"
doLast {
println "Partner"
}
}
println "5"
如果您是./gradlew partner
,您将看到:
> Configure project :
1
2
3
4
5
> Task :partner
Partner
如果您希望一个自定义任务依赖另一个任务怎么办? 这简单。 在两个自定义任务的定义之后, build.gradle
添加到build.gradle
文件中的某处。
partner.dependsOn howdy
并运行: ./gradlew partner
...
> Task :howdy
Howdy
> Task :partner
Partner
您还可以使用task属性finalizedBy
表示类似的关系。 如果用以下内容替换dependsOn
行:
howdy.finalizedBy partner
并运行: /gradlew howdy
。
...
> Task :howdy
Howdy
> Task :partner
Partner
am! 您好伙伴。
您得到相同的输出。 当然,他们表达不同的关系。
有很多选项。 这是Gradle令人困惑的声誉的部分来源。 Task API的Gradle文档是一个很好的参考。
关于任务的最后一点:在实践中,您很少编写自定义任务来说诸如“ Howdy Partner”之类的东西(我很难相信,我知道)。 实际上,通常您会覆盖已经定义的任务类型。 例如,Gradle定义了Copy
文件从一个位置复制到另一位置的Copy
任务。
这是一个将文档复制到构建目标的示例:
task copyDocs(type: Copy) {
from 'src/main/doc'
into 'build/target/doc'
}
当您意识到因为build.gradle
文件实际上是一个Groovy脚本时,Groovy和Gradle才真正发挥作用,您可以根据需要执行任意代码来过滤和转换这些文件。
下面的任务转换每个副本文件,并排除.DS_Store
文件。 DSL非常灵活。 您可以有多个from
块并excludes
,也可以执行诸如重命名文件或专门包含文件之类的操作。 再次查看“复制”任务的文档以获取更完整的想法。
task copyDocs(type: Copy) {
from 'src/main/doc'
into 'build/target/doc'
eachFile { file ->
doSomething(file);
}
exclude '**/.DS_Store'
}
在Gradle Jar
或War
,我最优先执行的任务是负责打包.jar
和.war
文件以进行最终分发的任务。 像“ Copy
任务一样,它们具有非常开放的能力来自定义流程,这对于需要自定义最终产品的项目可能是巨大的帮助。 实际上,您可以使用Gradle DSL来完全控制打包过程的各个方面。 (当然,强大的力量伴随着巨大的责任)。
Spring Boot插件的bootJar
和bootWar
任务继承自Jar
和War
任务,因此它们包括所有配置选项,包括复制,过滤和修改文件的能力以及自定义清单的能力。
创建一个OIDC应用程序
既然您是高级Gradle忍者(或者至少希望它不受Gradle DSL的威胁),现在该回到原始的Spring Boot项目了。
转到Okta开发人员仪表板以创建OpenID Connect应用程序。
单击应用程序顶部菜单。 单击添加应用程序按钮。
选择应用程序类型Web 。
单击下一步 。
为应用命名。 我将其命名为“ Spring Boot Gradle Demo”。
在登录重定向URI下,添加值: https://oidcdebugger.com/debug
: https://oidcdebugger.com/debug
。
在允许的授予类型下 ,单击隐式(混合)旁边的复选框。
其余的默认值将起作用。
单击完成 。
让页面保持打开状态,注意客户端ID 。 稍后您将需要它来生成JWT。
更新Spring Boot应用程序
您需要对Spring Boot应用程序进行一些更改。 首先,如果需要,从build.gradle
文件中删除所有Howdy Partner
资料。 它实际上并没有伤害任何东西,但现在不再是必需的。
将以下闭合添加到build.gradle
文件的底部:
processResources {
expand(project.properties)
}
这将配置Java
任务以将项目属性扩展到资源文件中。
如果您查看src/main/resources/application.yml
文件:
okta:
oauth2:
issuer: ${oauthIssuer}
您会注意到,我们需要填写两个属性。最好的方法是使用gradle.properties
文件。
在项目根目录中创建gradle.properties
文件:
oauthIssuer={yourIssuerUri}
您需要填写两个值。 客户端ID来自您刚创建的OIDC应用。 发行者URI如下所示: https://dev-123456.oktapreview.com/oauth2/default
: https://dev-123456.oktapreview.com/oauth2/default
,可以在Okta开发人员仪表板中找到。 转到API并选择“ 授权服务器” 。 在表中查找默认授权服务器和颁发者URI值。
使用OIDC调试器生成令牌
使用OIDC调试器为OIDC应用程序生成令牌。
您将需要填写:
- 授权URI与您的Okta开发人员URI匹配
- 客户端ID与OIDC应用程序客户端ID相匹配
- 声明什么都可以,只是不能空白。 在生产中, 状态有助于防止跨站点伪造请求,并且应该是CSRF令牌。
完成此操作后,向下滚动并点击发送请求 。
您应该看到成功屏幕。
复制访问令牌,打开终端,然后将其存储在shell变量中,如下所示:
export TOKEN=eyJraWQiOiJxMm5rZmtwUDRhMlJLV2REU2JfQ09LTlFD...
使用令牌运行请求
Spring Boot应用程序定义了一个控制器: HelloController.java
:
// ...
@RestController
public class HelloController { The Spring Boot app defines one contr
// REQUIRES AUTHENTICATION
@RequestMapping("/")
public String home(java.security.Principal user) {
return "Hello " + user.getName() + "!";
}
// DOES NOT REQUIRE AUTHENTICATION
@RequestMapping("/allow-anonymous")
public String anonymous() {
return "Hello whoever!";
}
}
有两个端点。 尽管从控制器文件本身来看并不明显,但/
端点需要身份验证,而/allow-anonymous
端点则不需要。 为此的配置在Application.java
文件的configure(HttpSecurity http)
方法中进行。 我将在这里介绍Spring Boot的细节,因为这不是本教程的重点,并且在其他博客文章中也对此进行了详细介绍(请参阅最后的链接)。
从一个单独的shell(而不是您刚刚保存了TOKEN
var的shell)中,使用以下命令运行Spring Boot应用程序:
./gradlew bootRun
回到带有TOKEN
var的外壳中,运行一个包含JWT的HTTP请求:
http :8080 "Authorization: Bearer $TOKEN"
您将获得一个HTTP 200:
HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
...
Hello andrew.hughes@example.com!
成功!
您可以在没有JWT的情况下运行请求以查看是否需要auth:
http :8080
HTTP/1.1 401
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
...
有关Spring Boot应用程序和身份验证/授权的更多详细信息,请查看最后的链接以获取更多博客文章。
下一步是编写一些测试并使用Gradle运行它们。
测试代码
创建一个测试文件: src/test/java/com/okta/springbootgradle/HelloControllerTest.java
package com.okta.springbootgradle;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"okta.oauth2.issuer=https://oauth.example.com/oauth2/default"})
@AutoConfigureMockMvc
public class HelloControllerTest {
@LocalServerPort
private int port;
@Autowired
private MockMvc mockMvc;
// test for auth required on home endpoine
@Test
public void homeShouldFail() throws Exception {
this.mockMvc
.perform(get("/"))
.andDo(print())
.andExpect(status().isUnauthorized());
}
// test home endpoint with auth
@Test
public void homeShouldPass() throws Exception {
this.mockMvc
.perform(get("/").with(user("Mister Tester")))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString("Hello Mister Tester!")));
}
// test anonymous endpoint
@Test
public void anonymous() throws Exception {
this.mockMvc
.perform(get("/allow-anonymous"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString("Hello whoever!")));;
}
}
该测试文件包含三个测试。 第一个测试检查本地端点,以确保不提供身份验证的请求失败并出现未授权错误。 第二个测试使用Spring MockMVC库提供身份验证并再次测试本地端点。 最后一个测试检查/allow-anonymous
端点。
使用以下./gradlew test
运行测试: ./gradlew test
输出非常小:
> Task :test
INFO [Thread-6] o.s.s.c.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
BUILD SUCCESSFUL in 7s
5 actionable tasks: 5 executed
如果您想查看更多信息,请尝试添加-i
标志,如下所示:
./gradlew test -i
使用Spring进行的测试本身就是一个完整的教程,因此我将其保留下来。 Spring的不错的指南介绍了一些测试Spring Boot REST服务的不同方法。
我永远不会宽恕这一点,但是如果您需要运行构建并希望跳过测试,则可以使用: gradle build -x test
。
像Gradle一样, Test
任务是高度可定制的。 您可以设置特定于测试的系统属性,配置JVM参数,更改堆大小,包括或排除特定测试等,等等。在Gradle页面上查看Test任务的文档 。
您还可以在master
分支的GitHub页面上查看项目的最终状态。
包起来
在本教程中,您学习了Gradle构建系统的基础知识。 您已经看到Gradle具有高度的灵活性和可定制性,可以与Groovy DSL或Kotlin DSL一起使用。 您在教程项目中查看了示例build.gradle
文件,并了解了如何配置典型的构建。 接下来,本教程深入探讨了闭包的世界,并了解了如何在Gradle DSL中使用它们来创建配置块。 之后,您使用Gradle包装器将项目构建系统封装在项目本身内,然后深入Gradle任务,创建自定义任务以及查看如何处理和执行任务。 还有更多! 哈哈。 然后,本教程向您展示了如何使用Gradle构建和运行一个简单的Spring Boot项目,以及如何使用Spring和Gradle定义和运行一些测试。
如所承诺的,如果您想了解有关Spring Boot和Java的更多信息,Okta博客将提供大量的出色教程:
- Java应用程序的简单令牌认证
- Java的Servlet身份验证
- 在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序
- 使用Java,MicroProfile和JWT身份验证构建REST API
- 创建一个安全的Spring REST API
- 使用Spring Boot和Vue.js构建一个简单的CRUD应用
如果您喜欢这篇文章,请在社交媒体{ Twitter , Facebook , LinkedIn , YouTube }上关注我们,以了解我们何时发布类似的帖子。
使用Gradle获取Groovy最初于2019年9月7日发布在Okta开发人员博客上。
朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK。 在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。
翻译自: https://www.javacodegeeks.com/2019/11/get-groovy-with-gradle.html