使用PostgreSQL使用Spring Boot和JPA构建基本应用

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

每个不平凡的应用程序都需要一种保存和更新数据的方法:可通过HTTP访问的资源服务器。 通常,必须保护此数据。 Java是一门伟大的语言,在专业,企业开发方面已有数十年的历史,对于任何应用程序的服务器堆栈都是绝佳的选择。 在Java生态系统内,Spring使为数据构建安全的资源服务器变得简单。 与Okta结合使用时,您可以使用Spring Security将经过专业维护的OAuth和JWT技术轻松集成到Spring Boot中。

在本文中,您将使用Spring Boot和Spring Data JPA构建资源服务器。 最重要的是,您将使用OAuth 2.0实现基于组的身份验证和授权层。 如果这听起来很复杂–不用担心! 不是。

在深入探讨之前,让我们介绍一下背景知识:

资源服务器是服务器功能和数据的编程访问点(与API服务器和/或REST服务器基本相同)。

JPA是Java Persistence API,它是使用Java管理关系数据库的规范。 它描述了Java类和关系数据库之间的抽象层。

Spring Data JPA是JPA提供程序(例如Hibernate)的包装。 正如您将看到的,它使持久化Java类就像添加一些注释和创​​建简单的存储库接口一样简单。 无需实际编写持久性或检索方法! 另一个很大的好处是您可以透明地更改基础数据库实现,而不必更改任何代码。 例如,在本教程中,您将使用Postgres,但稍后,如果您决定使用MySQL,您要做的就是更改一些依赖项。

安装PostgreSQL以实现JPA持久性

您需要为此教程安装PostgreSQL。 如果尚未安装,请转到其下载页面并进行安装。

接下来需要做的是为项目创建一个Postgres用户和数据库。 为此,您可以使用Postgres CLI。 您应该能够运行以下命令: psql -V并得到如下响应:

psql (PostgreSQL) 11.12

为您的JPA实体创建PostgreSQL数据库

在使用数据库之前,您需要做一些事情。 你需要:

  1. 为应用创建用户
  2. 为该用户设置密码
  3. 为应用创建数据库
  4. 为用户授予数据库特权

本教程使用jpatutorial作为用户名,并使用springbootjpa作为数据库名。 如果愿意,可以随意更改这些值,但是您必须记住在整个教程中都使用自定义值。

从终端输入psql进入Postgres shell。 然后输入以下命令。

创建一个用户

create user jpatutorial;

外壳程序应响应: CREATE ROLE

不要忘记分号! 我永远也不会这样做。 我绝对不是凭经验说话。 但是,如果你没有在分号键入psql不处理的命令,你可以在沮丧迷茫失去20-30分钟,不知道发生了什么事,直到进入一个分号,在这一点上,试图处理所有的命令。

给用户密码

alter user jpatutorial with encrypted password '<your really secure password>';

外壳程序应使用以下命令响应: ALTER ROLE

创建数据库

create database springbootjpa;

外壳程序应使用以下命令响应: CREATE DATABASE

授予特权

grant all privileges on database springbootjpa to jpatutorial;

外壳应以GRANT响应。

最后,如果需要,键入\q退出外壳。

如果您想了解更多有关psql ,可以看看Postgres的docs 。

构建一个Spring Boot资源服务器

从GitHub仓库克隆启动项目,并检出start分支:

git clone -b start https://github.com/oktadeveloper/okta-spring-boot-jpa-example.git

入门项目是一个全新的Spring Boot项目,仅具有一些Postgres特定的配置。 如果查看build.gradle文件,将看到PostgreSQL JPA连接器依赖性。 您还会注意到文件src/main/resources/hibernate.properties其唯一目的是摆脱对我们而言并不重要的烦人的警告/错误。 src/main/resources/application.yml文件还为您预先填充了一些属性。

继续并打开application.yml文件,并填写您为数据库用户创建的密码。 您还应该更新用户名,数据库名称和端口(如果它们不同)。

spring:  jpa:  hibernate:  ddl-auto: create  database-platform: org.hibernate.dialect.PostgreSQLDialect  datasource:  url: "jdbc:postgresql://localhost:5432/springbootjpa"  username: jpatutorial  password: < your password >

ddl-auto属性指定了加载时休眠的行为。 选项包括:

  • validate: 验证架构,但不做任何更改
  • 更新: 更新架构
  • create: 创建模式,销毁任何先前的数据
  • create-drop: 类似于create,但是在会话关闭时也会删除架构(用于测试)

您正在使用create 。 每次运行该程序时,都会从新表和数据开始创建一个新的数据库。

database-platform实际上是不必要的。 Spring Data / Hibernate可以自动检测平台。 但是,如果没有此属性,那么如果您在未启动Postgres服务器的情况下运行应用程序,则会得到一个非常无益的错误,即未添加此config属性而不是被告知要启动服务器。 发生这种情况是因为Hibernate无法自动检测数据库平台,因此在抱怨实际上没有正在运行的服务器之前先抱怨一下。

使用./gradlew bootRun运行应用程序。 您应该会看到以下内容:

2018-11-21 09:27:50.233  INFO 31888 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
2018-11-21 09:27:50.302  INFO 31888 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-11-21 09:27:50.308  INFO 31888 --- [           main] c.o.s.SpringBootJpaApplication           : Started SpringBootJpaApplication in 21.361 seconds (JVM running for 21.848)
<=========----> 75% EXECUTING [4m 26s]
> :bootRun

但是,它并没有做太多事情。 没有域模型,资源存储库或控制器类。

使用Spring Data和JPA添加域类

域或模型是您将存储的数据的程序表示形式。 Spring Data和JPA的神奇之处在于,Spring可以采用Java类并将其转换为数据库表。 它甚至会自动生成必要的加载和保存方法。 最好的部分是(或多或少)这与数据库无关。

您在本教程中使用的是PostgreSQL,并且可以通过更改build.gradle文件中的依赖项轻松地将其切换到MySQL。 当然,还要创建一个MySQL数据库并更新application.yml文件中的必要属性。 这对于测试,开发和长期维护非常有用。

继续阅读以学习如何开发一个简单的服务器来存储皮划艇类型。

com.okta.springbootjpa程序包中创建一个名为Kayak.java的Java文件。 您的皮划艇模型将具有名称,所有者,值和品牌/模型。

package com.okta.springbootjpa;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity // This tells Hibernate to make a table out of this class
@Data // Lombok: adds getters and setters
public class Kayak {public Kayak(String name, String owner, Number value, String makeModel) {this.name = name;this.owner = owner;this.value = value;this.makeModel = makeModel;}@Id@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;private final String name;private String owner;private Number value;private String makeModel;
}

该项目使用Lombok来避免必须编写大量的仪式获取器,设置器和诸如此类的东西。 您可以查看他们的文档 ,或更具体地说是您正在使用的@Data注释 。

@Entity注释告诉Spring此类是模型类,应转换为数据库表。

大多数属性可以自动映射。 但是, id属性用几个注释修饰,因为我们需要告诉JPA这是ID字段,并且应该自动生成它。

使用Spring Data JPA实现CRUD存储库

定义了域类后,Spring知道足以构建数据库表,但是它没有定义任何控制器方法。 没有数据的输出或输入。 Spring使添加资源服务器变得微不足道。 实际上,它是如此琐碎,您可能不会相信。

在包com.okta.springbootjpa ,创建一个名为KayakRepository.java的接口。

package com.okta.springbootjpa;import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;@RepositoryRestResource
public interface KayakRepository extends CrudRepository<Kayak, Integer> {
}

而已!
现在,您可以从资源服务器创建,读取,更新和删除皮划艇。 在短短的几秒钟内,您将精确地完成此操作,但在此之前,请进行其他更改。
将以下init()方法添加到SpringBootJpaApplication类中:

package com.okta.springbootjpa;import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;import java.text.NumberFormat;
import java.text.ParseException;
import java.util.stream.Stream;@SpringBootApplication
public class SpringBootJpaApplication {public static void main(String[] args) {SpringApplication.run(SpringBootJpaApplication.class, args);}@BeanApplicationRunner init(KayakRepository repository) {String[][] data = {{"sea", "Andrew", "300.12", "NDK"},{"creek", "Andrew", "100.75", "Piranha"},{"loaner", "Andrew", "75", "Necky"}};return args -> {Stream.of(data).forEach(array -> {try {Kayak kayak = new Kayak(array[0],array[1],NumberFormat.getInstance().parse(array[2]),array[3]);repository.save(kayak);}catch (ParseException e) {e.printStackTrace();}});repository.findAll().forEach(System.out::println);};}}

应用程序启动时将运行此方法。 它将一些样本数据加载到资源服务器中,只是为了让您在下一节中有所了解。

测试您的Spring Boot资源服务器

HTTPie是一个很棒的命令行实用工具,它使对资源服务器的请求运行变得容易。 如果未安装HTTPie,请使用brew install httpie进行brew install httpie 。 或前往他们的网站并实现它。 或者只是跟随。

确保您的Spring Boot应用正在运行。 如果不是,请使用./gradlew bootRun启动它。

针对您的资源服务器运行GET请求: http :8080/kayaks ,这是http GET http://localhost:8080/kayaks简写。

您会看到以下内容:

HTTP/1.1 200
Content-Type: application/hal+json;charset=UTF-8
Date: Wed, 21 Nov 2018 20:39:11 GMT
Transfer-Encoding: chunked{"_embedded": {"kayaks": [{"_links": {"kayak": {"href": "http://localhost:8080/kayaks/1"},"self": {"href": "http://localhost:8080/kayaks/1"}},"makeModel": "NDK","name": "sea","owner": "Andrew","value": 300.12},{"_links": {"kayak": {"href": "http://localhost:8080/kayaks/2"},"self": {"href": "http://localhost:8080/kayaks/2"}},"makeModel": "Piranha","name": "creek","owner": "Andrew","value": 100.75},{"_links": {"kayak": {"href": "http://localhost:8080/kayaks/3"},"self": {"href": "http://localhost:8080/kayaks/3"}},"makeModel": "Necky","name": "loaner","owner": "Andrew","value": 75}]},"_links": {"profile": {"href": "http://localhost:8080/profile/kayaks"},"self": {"href": "http://localhost:8080/kayaks"}}
}

此输出使您对Spring Boot资源返回的数据格式有了一个非常扎实的想法。 您也可以使用POST添加新的皮划艇。

命令:

http POST :8080/kayaks name="sea2" owner="Andrew" value="500" makeModel="P&H"

回复:

HTTP/1.1 201
Content-Type: application/json;charset=UTF-8
Date: Wed, 21 Nov 2018 20:42:14 GMT
Location: http://localhost:8080/kayaks/4
Transfer-Encoding: chunked{"_links": {"kayak": {"href": "http://localhost:8080/kayaks/4"},"self": {"href": "http://localhost:8080/kayaks/4"}},"makeModel": "P&H","name": "sea2","owner": "Andrew","value": 500
}

如果您再次列出皮划艇( http :8080/kayaks ),则会在列出的项目中看到新的皮划艇。

HTTP/1.1 200
Content-Type: application/hal+json;charset=UTF-8
Date: Wed, 21 Nov 2018 20:44:22 GMT
Transfer-Encoding: chunked{"_embedded": {"kayaks": [...{"_links": {"kayak": {"href": "http://localhost:8080/kayaks/4"},"self": {"href": "http://localhost:8080/kayaks/4"}},"makeModel": "P&H","name": "sea2","owner": "Andrew","value": 500}]},...
}

您也可以删除皮划艇。 运行以下命令: http DELETE :8080/kayaks/4这将删除ID = 4的皮划艇或我们刚刚创建的皮划艇。 第三次获取皮艇列表,您会发现它已经消失了。

使用Spring Boot,只需很少的代码,就可以创建功能全面的资源服务器。 此数据将持久保存到您的Postgres数据库中。

您可以使用Postgres命令外壳来验证这一点。 在终端上,键入psql进入shell,然后键入以下命令。

连接到数据库:

\connect springbootjpa
psql (9.6.2, server 9.6.6)
You are now connected to database "springbootjpa" as user "cantgetnosleep".

显示表内容:

SELECT * FROM kayak;
id | make_model |  name  | owner  |                                                                                   value
----+------------+--------+--------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------1 | NDK        | sea    | Andrew | \xaced0005737200106a6176612e6c616e67...8704072c1eb851eb8522 | Piranha    | creek  | Andrew | \xaced0005737200106a6176612e6c616e672e...0787040593000000000003 | Necky      | loaner | Andrew | \xaced00057372000e6a6176612e6c616e67...7870000000000000004b5 | P&H        | sea2   | Andrew | \xaced0005737200116a6176612e6...08b0200007870000001f4
(4 rows)

需要注意的几件事。 首先,请注意, 被存储为二进制对象,因为它被定义为Number类型而不是原始类型(double,float或int)。 其次,请记住,由于ddl-auto: create application.yml文件中的ddl-auto: create行,在application.yml每次启动时都将擦除此数据并重新创建整个表。

设置身份验证

Okta是软件即服务身份,身份验证和授权提供者。 虽然我确实从事过将所有项目外包给SaaS提供商的项目,但所产生的问题超出了其承诺解决的问题,但身份验证和授权是使这种模型完全有意义的地方。 在线安全很难。 发现漏洞,必须快速更新服务器。 标准变更和代码需要修改。 所有这些更改都有可能创建新的漏洞。 让Okta处理安全性意味着您可以担心使您的应用程序与众不同的事情。

为了向您展示设置的简便性,您将集成Okta OAuth并将基于令牌的身份验证添加到资源服务器。 如果尚未注册,请访问developer.okta.com并注册一个免费帐户。 拥有帐户后,通过单击“ 应用程序”顶部菜单项,然后单击“ 添加应用程序”按钮,打开开发人员仪表板并创建OpenID Connect(OIDC)应用程序

Spring Boot和JPA


选择单页应用程序

Spring Boot和JPA

默认应用程序设置很好,除了您需要添加登录重定向URIa 。 您将在稍后使用它来检索测试令牌。

另外,请注意您的客户ID ,稍后您将需要它。

Spring Boot和JPA

配置您的Spring Boot资源服务器以进行令牌认证

Okta使添加令牌身份验证到Spring Boot非常容易。 他们有一个名为Okta Spring Boot Starter的项目( 请查看GitHub项目 ),将整个过程简化为几个简单的步骤。

在您的build.gradle文件中添加几个依赖build.gradle

compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.0.RELEASE')  
compile('com.okta.spring:okta-spring-boot-starter:0.6.1')

将以下内容添加到build.gradle文件的底部(这解决了logback日志记录依赖性冲突)。

configurations.all {  exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'  exclude group: 'org.springframework.boot', module: 'logback-classic'  
}

接下来,你需要一些配置添加到您的application.yml文件,替换{yourClientId}从你1563 OIDC应用程序和客户端ID {yourOktaDomain}与1563网址。 像https://dev-123456.oktapreview.com东西。

okta:  oauth2:  issuer: https://{yourOktaDomain}/oauth2/default  client-id: {yourClientId}  scopes: openid profile email

最后,您需要将@EnableResourceServer批注添加到SpringBootVueApplication类。

import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;@EnableResourceServer  // <- add me
@SpringBootApplication  
public class SpringBootJpaApplication {  public static void main(String[] args) {  SpringApplication.run(SpringBootJpaApplication.class, args);  }...
}

测试受保护的Spring Boot服务器

停止您的Spring Boot服务器并使用以下./gradlew bootRun重新启动它: ./gradlew bootRun

从命令行运行一个简单的GET请求。

http :8080/kayaks

您会得到未经授权的401 /。

HTTP/1.1 401
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8{"error": "unauthorized","error_description": "Full authentication is required to access this resource"
}

生成访问令牌

要立即访问服务器,您需要一个有效的访问令牌。 您可以使用OpenID Connect调试器来帮助您完成此任务。 在另一个窗口中,打开oidcdebugger.com 。

授权URIhttps://{yourOktaUrl}/oauth2/default/v1/authorize ,其中{yourOktaUrl}替换为您的实际Okta预览URL。

重定向URI :不变。 这是您在上面的OIDC应用程序中添加的值。

客户ID :来自您刚创建的OIDC应用程序。

范围openid profile email

状态 :您要通过OAuth重定向过程传递的任何值。 我将其设置为{}

Nonce :可以一个人呆着。 Nonce表示“编号已使用一次”,是一种简单的安全措施,用于防止同一请求被多次使用。

响应类型token

响应方式form_post

Spring Boot和JPA


点击发送请求 。 如果您尚未登录developer.okta.com,则需要登录。如果(可能的话)已经登录,则将为您的登录身份生成令牌。

Spring Boot和JPA

使用访问令牌

您可以通过在Bearer类型的Authorization请求标头中包含令牌来使用令牌。

Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJfNVJr...

通过HTTPie发出请求:

http :8080/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1...'

添加基于组的授权

到目前为止,授权方案还算是二进制的。 该请求是否带有有效令牌。 现在,您将添加基于组的身份验证。 请注意,尽管有时在臭名昭著的网站上可以互换使用,但角色和组却不是一回事,它们是实现授权的不同方法。

角色是用户可以继承的权限集合的集合。 是一组标准权限分配给的用户的集合。 但是,在令牌的范围以及如何将Spring Security与JPA结合使用时,实现是完全相同的。 它们都以字符串“ authority”的形式从OAuth OIDC应用程序传递给Spring,因此目前它们基本上可以互换。 不同之处在于受保护的内容及其定义方式。

要在Okta中使用基于组的授权,您需要在访问令牌中添加一个“组”声明。 创建一个Admin组(“ 用户” >“ 组” >“ 添加组” )并将您的用户添加到其中。 您可以使用注册时使用的帐户,也可以创建一个新用户(“ 用户” >“ 添加人” )。 导航到“ API” >“ 授权服务器” ,单击“ 授权服务器”选项卡,然后编辑默认选项卡。 点击索赔标签,然后添加索赔 。 将其命名为“组”,并将其包含在访问令牌中。 将值类型设置为“ Groups”,并将过滤器设置为.*的正则表达式。

使用OIDC调试器创建一个新的访问令牌。 通过转到jsonwebtoken.io并输入生成的访问令牌,来查看已解码的令牌。

有效载荷看起来像这样:

{"ver": 1,"jti": "AT.Hk8lHezJNw4wxey1czypDiNXJUxIlKmdT16MrnLGp9E","iss": "https://dev-533919.oktapreview.com/oauth2/default","aud": "api://default","iat": 1542862245,"exp": 1542866683,"cid": "0oahpnkb44pcaOIBG0h7","uid": "00ue9mlzk7eW24e8Y0h7","scp": ["email","profile","openid"],"sub": "andrew.hughes@mail.com","groups": ["Everyone","Admin"]
}

声明包含用户分配到的组。 您用来登录developer.okta.com网站的用户也将是“所有人”组和“管理员”组的成员。

为了使Spring Boot和资源服务器在基于组的授权下都能正常运行,您需要对代码进行一些更改。

首先,在com.okta.springbootjpa包中添加一个名为SecurityConfiguration的新Java类。

package com.okta.springbootjpa;import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
}

需要此配置类来启用@PreAuthorize批注,该批注将用于基于组成员身份保护资源服务器。

接下来,将@PreAuthorize批注添加到KayakRepository ,如下所示:

...
import org.springframework.security.access.prepost.PreAuthorize;
...@RepositoryRestResource  
@PreAuthorize("hasAuthority('Admin')")  
public interface KayakRepository extends CrudRepository<Kayak, Long> {  
}

最后,在SpringBootJpaApplication删除 ApplicationRunner init(KayakRepository repository)方法(或仅注释掉@Bean批注)。 如果跳过此步骤,构建将失败,并显示以下错误:

AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

@PreAuthorize批注实际上阻止init()方法以编程方式创建自举数据,因为没有用户登录。因此,该方法运行时会引发错误。

请注意,您在@PreAuthorize批注中使用hasAuthority() ,而不是 hasRole() 。 区别在于hasRole()期望组或角色在ALL CAPS中并且具有ROLE_前缀。 这可以被配置,当然,但hasAuthority()来没有这个包袱,简单地检查任何权利要求你定义为okta.oauth2.roles-claimapplication.yml

在您的Spring Boot应用程序中测试管理员用户

重新启动您的Spring Boot应用程序(以./gradlew bootRun )。

尝试未经身份验证的GET请求:v class =“ highlighter-rouge”> http:8080 / kayaks。

HTTP/1.1 401
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8{"error": "unauthorized","error_description": "Full authentication is required to access this resource"
}

使用令牌尝试一下。

命令:

http :8080/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJf...'

回复:

HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/hal+json;charset=UTF-8{"_embedded": {"kayaks": []},"_links": {"profile": {"href": "http://localhost:8080/profile/kayaks"},"self": {"href": "http://localhost:8080/kayaks"}}
}

有效! 我们没有任何皮划艇,因为我们必须删除上面的init()方法,因此_embedded.kayaks数组为空。

提示:今后,如果您不想复制并粘贴整个巨大的令牌字符串,则可以将其存储到shell变量中,然后像这样重用它:

TOKEN=eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJf...
http :8080/kayaks 'Authorization: Bearer $TOKEN'

创建一个非管理员用户

为了演示基于组的授权,您需要在Okta上创建一个不是管理员的新用户。 转到developer.okta.com仪表板。

从顶部菜单中,选择“ 用户人员”

单击添加人按钮。

给用户一个名字姓氏用户名 (也将是主要电子邮件 )。 值无关紧要,并且您将不必检查电子邮件。 您只需要知道电子邮件地址/用户名和密码,即可在一分钟内登录Okta。

密码 :将下拉菜单更改为“ 由管理员设置”

为用户分配密码。

点击保存

您刚刚创建的用户不是Admin组的成员,而是默认组Everyone的成员。

在Spring Boot应用程序中基于测试组的授权

注销您的Okta开发人员仪表板。

返回OIDC调试器并生成一个新令牌。

这次,以新的非管理员用户身份登录。 系统会要求您选择一个安全问题,然后将您重定向到https://oidcdebugger.com/debug页面,您可以在其中复制令牌。

如果愿意,可以转到jsonwebtoken.io并解码新令牌。 在有效内容中, 声明将显示用户的电子邮件/用户名,而声明将仅显示“ 所有人”组。

{..."sub": "test@gmail.com","groups": ["Everyone"]
}

如果使用新令牌在/kayaks端点上发出请求,则会收到403 / Access Denied。

http :8080/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJX...'
HTTP/1.1 403
...{"error": "access_denied","error_description": "Access is denied"
}

为了演示@PreAuthorize批注的真正功能,请创建一个方法级别的安全约束。 将KayakRepository类更改为以下内容:

@RepositoryRestResource  
public interface KayakRepository extends CrudRepository<Kayak, Long> {  @PreAuthorize("hasAuthority('Admin')")  <S extends Kayak> S save(S entity);  }

这仅将save()方法限制为Admin组的成员。 仅需身份验证即可限制存储库的其余部分,而无需特定的组成员身份。

重新启动Spring Boot服务器。 再次运行相同的请求。

http :8080/kayaks 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJX...'
HTTP/1.1 200
...{"_embedded": {"kayaks": []},"_links": {"profile": {"href": "http://localhost:8080/profile/kayaks"},"self": {"href": "http://localhost:8080/kayaks"}}
}

_.embedded.kayaks存储库为空,因此_.embedded.kayaks是一个空数组。

尝试创建一个新的皮划艇。

http POST :8080/kayaks name="sea2" owner="Andrew" value="500" makeModel="P&H" "Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJX..."

您将获得另一个403。“保存”在此处等于HTML POST。

但是,如果您使用从原始管理员帐户生成的令牌,则可以使用。

注意:您的令牌可能已过期,您必须再次注销developer.okta.com,然后在OIDC调试器上重新生成令牌。

使用您的管理员帐户生成的令牌发布新的皮划艇。

这次您将获得201。

HTTP/1.1 201
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
...{"_links": {"kayak": {"href": "http://localhost:8080/kayaks/1"},"self": {"href": "http://localhost:8080/kayaks/1"}},"makeModel": "P&H","name": "sea2","owner": "Andrew","value": 500
}

成功!

看一下Spring Data的CrudRepository接口,以了解可以被覆盖的方法以及分配给方法级安全性的方法。 @PreAuthorize注释不仅可以用于组,还可以使用更多的内容。 可以利用Spring的表达语言(SpEL)的全部功能。

public interface CrudRepository<T, ID> extends Repository<T, ID> {<S extends T> S save(S entity);<S extends T> Iterable<S> saveAll(Iterable<S> entities);Optional<T> findById(ID id);boolean existsById(ID id);Iterable<T> findAll();Iterable<T> findAllById(Iterable<ID> ids);long count();void deleteById(ID id);void delete(T entity);void deleteAll(Iterable<? extends T> entities);void deleteAll();
}

就是这样! 很酷吧? 在本教程中,您将建立一个PostgreSQL数据库,创建一个Spring Boot资源服务器,该服务器使用Spring Data和JPA来持久化数据模型,然后将该数据模型转换为REST API,只需很少的代码。 此外,您还使用Okta向服务器应用程序添加了OIDC身份验证和OAuth 2.0授权。 最后,您实现了一个简单的基于组的授权方案。

如果您想查看这个完整的项目,可以在GitHub上的仓库中找到@ oktadeveloper / okta-spring-boot-jpa-example 。

请留意本系列中的下一篇文章,该文章将介绍在Spring WebFlux中使用NoSQL数据库(MongoDB)。

了解有关Spring Boot,Spring Security和安全身份验证的更多信息

如果您想了解有关Spring Boot,Spring Security或现代应用程序安全性的更多信息,请查看以下任何出色的教程:

  • Spring Boot,OAuth 2.0和Okta入门
  • 15分钟内将单一登录添加到您的Spring Boot Web App
  • 使用多重身份验证保护您的Spring Boot应用程序安全
  • 使用Spring Boot和GraphQL构建安全的API

如果您想深入研究,请查看Okta Spring Boot Starter GitHub项目 。

这对于Spring Data和保护Spring Boot项目是一个很好的参考: https : //docs.spring.io/spring-data/rest/docs/current/reference/html/

当将PostgreSQL与JPA和Hibernate一起使用时, Vlad Mihalcea有一个很棒的教程,标题为《 9个高性能技巧》 。

Baeldung有一个关于保护Spring Data / Spring Boot项目中的方法的有用教程: https ://www.baeldung.com/spring-security-method-security

最后,如果您需要在Mac OS X上使用PostgreSQL的更多帮助,请参阅此codementor.io教程 。

如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容, 请在Twitter上关注@oktadev , 在Facebook上关注我们,或订阅我们的YouTube频道 。

``使用PostgreSQL使用Spring Boot和JPA构建应用程序''最初于2018年12月13日发布在Okta开发者博客上。

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

翻译自: https://www.javacodegeeks.com/2018/12/build-basic-spring-boot-using-postgresql.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/345126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过示例了解Apache Ignite Baseline拓扑

点燃基准拓扑或BLT表示群集中的一组服务器节点&#xff0c;这些服务器节点将数据持久存储在磁盘上。 其中&#xff0c;N1-2和N5服务器节点是具有本机持久性的Ignite集群的成员&#xff0c;这些集群使数据能够持久存储在磁盘上。 N3-4和N6服务器节点是Ignite群集的成员&#x…

Spring Boot集成测试中@ContextConfiguration和@SpringApplicationConfiguration之间的区别

即使同时使用ContextConfiguration和SpringApplicationConfiguration批注以及SpringJUnit4ClassRunner来指定如何加载Spring应用程序上下文&#xff0c;它们之间也存在细微的差异。 尽管ContextConfiguration在加载应用程序上下文方面表现出色&#xff0c;但没有充分利用Spring…

vert.x_使用vert.x 2.0,RxJava和mongoDB创建simpe RESTful服务

vert.x中断了将近半年后发表了一篇新文章。 在本文中&#xff0c;我们将快速了解如何开始使用vert.x&#xff0c;更有趣的是&#xff0c;如何使用RxJava简化异步系统的编程。 我们将涵盖以下主题&#xff1a; 使用Maven创建一个空的vert.x项目 导入IntelliJ并创建一个简单的H…

如何通过Rultor将Maven工件部署到CloudRepo

在我以前的文章中 &#xff0c;我描述了如何在Amazon S3中设置私有Maven存储库并通过Rultor进行部署。 如果您熟悉管理Amazon Web Services&#xff08;AWS&#xff09;&#xff0c; S3和AWS Identity and Access Management&#xff08;IAM&#xff09;的话&#xff0c;这是一…

java里面自行车的属性_11、Java基础知识

1、安装jdk&#xff0c;配置环境变量2、public class HelloWorld{publicstatic void main(String[] args){System.out.println(‘HelloWorld’);}}3、编译过程&#xff1a;通过javac编译java文件&#xff0c;生成.class文件&#xff0c;使用java命令运行class文件&#xff0c;注…

布线问题分支限界法java_大型布线:Java云应用程序缺少的技术

布线问题分支限界法java您是否曾经想过&#xff0c;为什么大多数Java框架中的依赖项注入仅用于本地进程内服务而不是分布式服务&#xff1f; 我最近在2013年EMC世界大会上遇到了Paul Maritz的主题演讲 &#xff08;跳至第32分钟&#xff09;&#xff0c;这使我在云平台的背景下…

Spring Boot微服务,Docker和Kubernetes研讨会–第2部分

在上一篇文章中&#xff0c;我们使用SpringBoot和Docker创建了第一个微服务“ ProductService”。 在这一部分中&#xff0c;我们将详细介绍如何使用Spring Cloud&#xff0c;netflix库&#xff0c;API网关来管理多个微服务。 假设对于我们的订单管理系统&#xff0c;最小关系…

jboss5.1安全性配置_使用Java EE安全性和JBoss AS 7.x保护JSF应用程序的安全

jboss5.1安全性配置企业应用程序的一个常见要求是在登录页面后面保护所有JSF页面。 有时&#xff0c;您甚至希望在应用程序内部具有保护区&#xff0c;只有拥有特定角色的用户才能访问这些保护区。 Java EE标准附带了实现受某些安全性约束保护的Web应用程序所需的所有方法。 在…

分布式事务 camel_使用Camel在Amazon上构建分布式工作流应用程序

分布式事务 camel带有SNS-SQS的管道 工作流由以动态条件确定的特定顺序执行的独立任务组成。 工作流通常代表业务流程&#xff0c;例如电子商务商店中的订单处理步骤。 Amazon Web Services提供了用于构建分布式和可伸缩工作流应用程序的各种工具。 构建此类应用程序的一种方法…

比较Java REST文档框架

确定在记录REST API时选择哪种Java框架可能很麻烦。 在本博文中&#xff0c;我们将简要比较我们自己使用的REST Web服务的三种文档框架&#xff0c;以及它们如何与Spring框架&#xff08;这是Foreach最常使用的Java框架&#xff09;集成。 这些是RESTful API建模语言&#xff0…

jaVa游戏三国志英杰传,《三国志英杰传》到底是怎样的一款游戏

原标题&#xff1a;《三国志英杰传》到底是怎样的一款游戏介绍作为PC平台上经典的战棋策略类游戏&#xff0c;英杰传系列可谓把这一类型游戏在战略性和资源获取上的精髓发挥的淋漓尽致。系列初代的《三国志英杰传》诞生在1995年的DOS系统上&#xff0c;虽然我接触英杰传时已经是…

jvm 内存镜像_镜像镜像–使用反射在运行时查看JVM内部

jvm 内存镜像开发人员&#xff1a;Takipi会告诉您何时新代码在生产中中断– 了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射。 它是Java和Scala编程的主要方面&#xff0c;它使我们使用的库可以与我们的代码进行交互&#xff0c;而无需对其进行硬…

谁去过顽皮,谁去过尼斯? 圣诞老人为您提供Java 11建议!

有没有想过圣诞老人如何为世界各地的孩子们送上节日礼物&#xff1f; 有20亿个孩子&#xff0c;每个孩子都有自己的愿望清单&#xff0c;他会在24小时内完成。 这意味着每个孩子平均需要43微秒&#xff0c;他需要检查每个孩子是否顽皮或好。 您无需再怀疑了。 我会透露这个秘密…

php时间格式函数,PHP函数之日期时间函数date()使用详解_php基础_脚本

$ttime();echo date("Y-m-d H:i:s",$t);第一个参数的格式分别表示:a - "am" 或是 "pm"A - "AM" 或是 "PM"d - 几日&#xff0c;二位数字&#xff0c;若不足二位则前面补零; 如: "01" 至 "31"D - 星期几…

play框架配置 拦截器_如何使用Play框架为https配置SSL证书

play框架配置 拦截器我花了几个小时试图使它起作用&#xff0c;最后&#xff0c;问题是我自己没有使用keytool生成CSR&#xff08;证书请求&#xff09;。 当我尝试通过https访问Play时&#xff0c;我一直收到此错误&#xff1a; javax.net.ssl.SSLPeerUnverifiedException&a…

matlab 球坐标绘图,MATLAB绘制地图

1使用向量绘制地图1.1绘制全球海岸线向量数据可以表示一个地图。这种向量存在的形式是一系列的经纬度或投影坐标对&#xff0c;它们代表一个点集、一个线条或者多边形。例如&#xff0c;描绘出行政区域边界的点、公路系统、城市的中心或者以上三个集合放在一起&#xff0c;都可…

php 有 stringbuffer,String、StringBuffer、StringBulider三者介绍

三者都实现了CharSequence接口&#xff0c;因此CharSequence可认为是一个字符串的协议接口1.String类是不可变类&#xff0c;即一旦一个String对象被创建后&#xff0c;包含在这个对象中的字符序列是不可改变的&#xff0c;直至这个对象被销毁&#xff1b;我们常常定义的时候 S…

php生成网页按钮,JavaScript实现自动生成网页元素功能(按钮、文本等)_javascript技巧...

创建元素的方法&#xff1a;1、利用createTextNode()创建一个文本对象2、利用createElement()创建一个标签对象3、直接利用容器标签中的一个属性&#xff1a;innerHTML-----本质上改该标签容器中的“html代码”&#xff0c;不是我们认为的对象树的操作详解代码&#xff1a;这是…

adf 自动输稿器_在ADF实体PK属性中使用MySQL自动增量PK列

adf 自动输稿器大家好。 继续进行ADF MySQL解决方法系列&#xff0c;今天我们将看到需要做些什么才能将MySQL PK自动增量列与ADF实体PK属性一起使用。 如果使用的是Oracle数据库&#xff0c;则可以使用oracle.jbo.domain.DBSequence以及序列和触发器来立即进行操作。 为简单起…

探索适用于Apache Spark的Spline Data Tracker和可视化工具(第1部分)

最近引起我注意的一个有趣且充满希望的开源项目是Spline &#xff0c;它是由Absa维护的Apache Spark的数据沿袭跟踪和可视化工具。 该项目由两部分组成&#xff1a;一个在驱动程序上工作的Scala库&#xff0c;该驱动程序通过分析Spark执行计划来捕获数据沿袭&#xff0c;并提供…