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

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

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

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

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

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

Spring Data JPA is a wrapper around JPA providers such as Hibernate. As you’ll see, it makes persisting your Java classes as simple as adding some annotations and creating a simple repository interface. No need to actually write persistence or retrieval methods! Another great benefit is that you can change the underlying database implementation transparently without having to change any code. For example, in this tutorial, you’ll be using Postgres, but later if you decided you’d rather use MySQL, all you’d have to do is change out some dependencies.

Install PostgreSQL for JPA Persistence

You’ll need to have PostgreSQL installed for this tutorial. If you don’t already have it installed, go to their downloads page and install it.

接下来,您需要为该项目创建一个Postgres用户和数据库。 为此,您可以使用Postgres CLI,psql。

您应该能够运行以下命令:psql -V并得到如下响应:

psql (PostgreSQL) 11.12

Create a PostgreSQL Database for Your JPA Entities

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

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

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

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

Create a user

create user jpatutorial;

外壳程序应使用以下命令响应:创建角色。

不要忘记分号!我永远也不会这样做。 我绝对不是凭经验说话。 但是,如果您不输入分号psql不会处理该命令,您可能会迷失20到30分钟,以至于困惑到底是怎么回事做输入分号,此时它将尝试处理所有命令。

Give the user a password

alter user jpatutorial with encrypted password '';

外壳程序应使用以下命令响应:改变角色。

Create the database

create database springbootjpa;

外壳程序应使用以下命令响应:创建数据库。

Grant privileges

grant all privileges on database springbootjpa to jpatutorial;

外壳应该以格兰特。

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

If you want to read more about psql you can take a look at Postgres’ docs.

Build a Spring Boot Resource Server

从GitHub存储库克隆入门项目,并检查开始科:

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 property specifies hibernate’s behavior upon loading. 的options are:

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

您正在使用创建. Each time the program is run, a new database is 创建d, starting with fresh tables and data.

数据库平台实际上是不必要的。 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

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

Add a Domain Class with Spring Data and JPA

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

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

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

在中创建一个Java文件com.okta.springbootjpa包称为Kayak.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;
}

This project uses Lombok to avoid having to code a bunch of ceremony getters and setters and whatnots. You can check out their docs, or more specifically for the @Data annotation you’re using.

的@实体注解告诉Spring此类是模型类,应该转换为数据库表。

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

Implement a CRUD Repository with Spring Data JPA

定义了域类后,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> {
}

而已!

现在,您可以从资源服务器创建,读取,更新和删除皮划艇。 只需一秒钟,您就可以完成此操作,但是在此之前,请进行其他更改。

添加以下内容在里面()方法SpringBootJpa应用程序类:

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);
    }

  @Bean
  ApplicationRunner 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);
    };
  }

}

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

Test Your Spring Boot Resource Server

HTTPie is a great command line utility that makes it easy to run requests against the resource server. If you don’t have HTTPie installed, install it using brew install httpie. Or head over to their website and make it happen. Or just follow along.

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

针对您的资源服务器运行GET请求:http:8080 /皮划艇,是的简写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 /皮划艇),您会在列出的项目中看到新的皮划艇。

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删除:8080 / kayaks / 4。 这将删除ID = 4的皮艇或我们刚刚创建的皮艇。 第三次获取皮划艇列表,您会发现它已经消失了。

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

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

连接到数据库:

\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...8704072c1eb851eb852
  2 | Piranha | creek | Andrew | \xaced0005737200106a6176612e6c616e672e...078704059300000000000
  3 | Necky | loaner | Andrew | \xaced00057372000e6a6176612e6c616e67...7870000000000000004b
  5 | P&H | sea2 | Andrew | \xaced0005737200116a6176612e6...08b0200007870000001f4
(4 rows)

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

Set Up Authentication

Økta is a software-as-service identity, authentication, and authorization provider. While I have definitely worked on projects where outsourcing everything to SaaS providers created more problems than it promised to solve, authentication and authorization is a place where this model makes total sense. Online security is hard. Vulnerabilities are found and servers must be updated quickly. Standards change and code needs modification. All of these changes have the potential to create new vulnerabilities. Letting Okta handle security means that you can worry about the things that make your application unique.

To show you how easy it is to set up, you’re going integrate Okta OAuth and add token-based authentication to the resource server. If you haven’t already, head over to developer.okta.com and sign up for a free account. Once you have an account, open the developer dashboard and create an OpenID Connect (OIDC) application by clicking on the Application top-menu item, and then on the Add Application button.

使用PostgreSQL使用Spring Boot和JPA构建基本应用_第1张图片

选择单页应用。

使用PostgreSQL使用Spring Boot和JPA构建基本应用_第2张图片

默认的应用程序设置很好,除了您需要添加一个登录重定向URI:一种. You’re going to use this in 一种 moment to retrieve 一种 test token.

另外,请注意客户编号,因为稍后您会需要。

使用PostgreSQL使用Spring Boot和JPA构建基本应用_第3张图片

Configure Your Spring Boot Resource Server for Token Authentication

Okta has made adding token authentication to Spring Boot super easy. They have a project called Okta Spring Boot Starter (check out the GitHub project) that simplifies the whole process to a few simple steps.

给你的依赖添加几个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}与来自Okta OIDC应用程序的客户端ID以及{yourOktaDomain}与您的Okta URL。 就像是https://dev-123456。oktapreview。com。

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

最后,您需要添加@EnableResourceServer您的注释SpringBootVue应用程序类。

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);  
    }
    ...
}

Test the Protected Spring Boot Server

停止您的Spring Boot服务器并使用以下命令重新启动它:。/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"
}

Generate an Access Token

To access the server now, you need a valid access token. You can use OpenID Connect Debugger to help you do this. In another window, open oidcdebugger.com.

授权URI:https:// {yourOktaUrl} / oauth2 / default / v1 / authorize,带有{yourOktaUrl}替换为您的实际Okta预览URL。

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

客户编号:通过您刚创建的OIDC应用程序。

范围:openid个人资料电子邮件。

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

随机数: can be left alone. 随机数 means “number used once” and is a simple security measure used to prevent the same request from being used multiple times.

回应类型:代币。

反应模式:form_post。

使用PostgreSQL使用Spring Boot和JPA构建基本应用_第4张图片

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

使用PostgreSQL使用Spring Boot和JPA构建基本应用_第5张图片

Use the Access Token

您可以通过以下方式使用令牌:授权书类型的请求标头承载者。

Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJfNVJr...

通过HTTPie发出请求:

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

Add Group-based Authorization

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

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

要在Okta中使用基于组的授权,您需要在访问令牌中添加一个“组”声明。 创建一个管理员组(用户数 > 团体 > 新增群组),并将您的用户添加到其中。 您可以使用注册时使用的帐户,也可以创建一个新用户(用户数 > 加人)。 导航API > 授权服务器, 点击授权服务器标签并编辑默认选项卡。 点击索偿标签和添加声明。 Name it “groups”, and include it in the access token。 Set the value type to “团体” and set the filter to be a Regex of 。*。

Create a new access token using OIDC Debugger. Take a look at your decoded token by going to jsonwebtoken.io and entering in your generated access token.

有效载荷看起来像这样:

{
 "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": "[email protected]",
 "groups": [
  "Everyone",
  "Admin"
 ]
}

的团体 claim carries the 团体 to which the user is assigned. 的user you’re using to sign in to the developer.okta.com website will also be a member of both the “Everyone” group and the “Admin” group.

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

首先,在com。okta。springbootjpa包称为安全配置。

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的注释皮划艇仓库,就像这样:

...
import org.springframework.security.access.prepost.PreAuthorize;
...

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

最后,在SpringBootJpa应用程序,删除的ApplicationRunner初始化(KayakRepository存储库) method (or just comment out的@豆 annotation). If you skip this step,the build will fail with的following error:

 AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

的@PreAuthorize批注实际上阻止了在里面()方法,因为没有用户登录,因此通过编程方式创建引导数据。因此,该方法运行时会引发错误。

请注意,您正在使用hasAuthority()在里面@PreAuthorize注释和不hasRole()。ThedifferenceisthathasRole()expectsgroupsorrolestobeinALLCAPSandtohavea角色_prefix。Thiscanbeconfigured,ofcourse,buthasAuthority()comeswithoutthisbaggageandsimplycheckswhateverclaimyou’vedefinedastheokta。oauth2。roles-claiminyourapplication。yml。

Test the Admin User in Your Spring Boot App

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

尝试未经身份验证的GET请求:http:8080 /皮划艇。

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"
        }
    }
}

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

小费:展望未来,如果您不想复制并粘贴整个巨大的令牌字符串,则可以将其存储到shell变量中,然后像这样重复使用:

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

Create a Non-Admin User

To demonstrate group-based authorization, you need to create a new user on Okta that isn’t an admin. Go to the developer.okta.com dashboard.

在顶部菜单中,选择用户数和人。

点击加人按钮。

给用户一个名字,姓,and 用户名(这也将是主要邮箱). The values do not matter,and you won’t need to be able to check the email. You simply need to know the email address/username and password so you can log in to Okta in a minute.

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

为用户分配密码。

请点击保存。

您刚刚创建的用户不是该用户的成员管理员组,但是默认组的成员大家。

Test Group-based Authorization in Your Spring Boot App

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

Return to the OIDC Debugger and generate a new token.

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

If you like, you can go to jsonwebtoken.io and decode your new token. In the payload, the sub claim will show the email/username of the user, and the groups claim will show only the Everyone group.

{
 ...
 "sub": "[email protected]",
 "groups": [
  "Everyone"
 ]
}

如果您使用新令牌在/皮划艇端点,您将获得403 /拒绝访问权限。

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


HTTP/1.1 403
...

{
    "error": "access_denied",
    "error_description": "Access is denied"
}

展示其真正的力量@PreAuthorize注释,创建方法级别的安全约束。 改变皮划艇仓库类如下:

@RepositoryRestResource  
public interface KayakRepository extends CrudRepository<Kayak, Long> {  

    @PreAuthorize("hasAuthority('Admin')")  
    <S extends Kayak> S save(S entity);  

}

这仅限制了保存()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是一个空数组。

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

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

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

但是,如果您使用从原始管理员帐户生成的令牌,则该令牌将起作用。

ñOTE: It’s possible your token will be expired and you’ll have to log out of developer.okta.com again and re-generate the token on the OIDC Debugger.

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

这次您将获得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
}

成功!

Take a look at Spring Data’s CrudRepository interface to get an idea of the methods that can be overridden and assigned method-level security. The @PreAuthorize annotation can be used with a lot more than just groups, as well. The entire power of Spring’s expression language (SpEL) can be leveraged.

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授权。 最后,您实现了一个简单的基于组的授权方案。

If you’d like to check out this complete project, you can find the repo on GitHub at @oktadeveloper/okta-spring-boot-jpa-example.

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

Learn More about Spring Boot, Spring Security, and Secure Authentication

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

  • Get Started with Spring Boot, OAuth 2.0, and Okta
  • Add Single Sign-On to Your Spring Boot Web App in 15 Minutes
  • Secure Your Spring Boot Application with Multi-Factor Authentication
  • Build a Secure API with Spring Boot and GraphQL

If you want to dive deeper, take a look at the Okta Spring Boot Starter GitHub project.

This is a great reference for Spring Data and securing Spring Boot projects: https://docs.spring.io/spring-data/rest/docs/current/reference/html/.

Vlad Mihalcea has a great tutorial titled 9 High-Performance Tips when using PostgreSQL with JPA and Hibernate.

Baeldung has a helpful tutorial on securing methods in Spring Data / Spring Boot projects: https://www.baeldung.com/spring-security-method-security.

Lastly, if you need some more help with PostgreSQL on Mac OS X, see this codementor.io tutorial.

If you have any questions about this post, please add a comment below. For more awesome content, follow @oktadev on Twitter, like us on Facebook, or subscribe to our YouTube channel.

from: https://dev.to//oktadev/build-a-basic-app-with-spring-boot-and-jpa-using-postgresql-ke9

你可能感兴趣的:(使用PostgreSQL使用Spring Boot和JPA构建基本应用)