Рубрики
Без рубрики

Создайте базовое приложение с помощью Spring Boot и JPA с использованием PostgreSQL

Создайте сервер ресурсов с использованием Spring Boot и Spring Data JPA и реализуйте групповую авторизацию с использованием Okta OAuth. С тегами безопасность, java, учебник, sql.

Каждому нетривиальному приложению необходим способ сохранения и обновления данных: сервер ресурсов, доступный по протоколу HTTP. Как правило, эти данные должны быть защищены. Java – отличный язык с десятилетней историей профессионального и корпоративного развития, и он является отличным выбором для стека серверов любого приложения. В экосистеме Java Spring упрощает создание безопасных серверов ресурсов для ваших данных. В сочетании с Okta вы получаете профессионально поддерживаемые технологии OAuth и JWT, которые легко интегрируются в Spring Boot с помощью Spring Security.

В этом посте вы собираетесь создать сервер ресурсов с использованием Spring Boot и Spring Data JPA. Кроме того, вы собираетесь реализовать уровень аутентификации и авторизации на основе групп с использованием OAuth 2.0. Если это звучит сложно – не волнуйтесь! Это не.

Прежде чем мы углубимся, давайте рассмотрим некоторые предыстории:

/|сервер ресурсов – это программная точка доступа к функциям и данным вашего сервера (в основном такая же, как сервер API и/или, возможно, сервер REST).

JPA – это API сохраняемости Java, спецификация для управления реляционными базами данных с использованием Java. Он описывает уровень абстракции между классами Java и реляционной базой данных.

Spring Data JPA – это оболочка для поставщиков JPA, таких как Hibernate. Как вы увидите, это делает сохранение ваших классов Java таким же простым, как добавление некоторых аннотаций и создание простого интерфейса репозитория. Нет необходимости на самом деле писать методы сохранения или поиска! Еще одним большим преимуществом является то, что вы можете прозрачно изменять базовую реализацию базы данных без необходимости изменять какой-либо код. Например, в этом уроке вы будете использовать Postgres, но позже, если вы решите, что предпочитаете использовать MySQL, все, что вам нужно будет сделать, это изменить некоторые зависимости.

Установите PostgreSQL для сохранения JPA

Для этого урока вам потребуется установить PostgreSQL. Если он у вас еще не установлен, перейдите на их страницу загрузки и установите его.

Следующее, что вам нужно будет сделать, это создать пользователя Postgres и базу данных для проекта. Для этого вы можете использовать интерфейс командной строки Postgres, psql .

Вы должны быть в состоянии выполнить следующую команду: psql -V и получить ответ, подобный:

psql (PostgreSQL) 11.12

Создайте базу данных PostgreSQL для Ваших объектов JPA

Прежде чем вы сможете использовать свою базу данных, вам нужно сделать несколько вещей. Вам нужно:

  1. Создайте пользователя для приложения
  2. Установите пароль для этого пользователя
  3. Создайте базу данных для приложения
  4. Предоставить пользователю права доступа к базе данных

В этом руководстве используется jpa tutorial для имени пользователя и spring boot jpa для имени базы данных. Не стесняйтесь изменять их, если хотите, но вам придется не забывать использовать свои пользовательские значения на протяжении всего урока.

Введите psql с терминала, чтобы войти в оболочку Postgres. Затем введите следующую команду.

Создание пользователя

create user jpatutorial;

Оболочка должна ответить: СОЗДАТЬ РОЛЬ .

Не забудьте точку с запятой! Я бы никогда, никогда этого не сделал. Я определенно говорю не по собственному опыту. Но если вы не введете точку с запятой psql не обработает команду, и вы можете потерять 20-30 минут в разочарованном замешательстве, задаваясь вопросом, что происходит пока ты do введите точку с запятой, после чего он попытается обработать все ваши команды.

Дайте пользователю пароль

alter user jpatutorial with encrypted password '';

Оболочка должна ответить: ИЗМЕНИТЬ РОЛЬ .

Создайте базу данных

create database springbootjpa;

Оболочка должна ответить: СОЗДАТЬ БАЗУ ДАННЫХ .

Предоставлять привилегии

grant all privileges on database springbootjpa to jpatutorial;

Оболочка должна ответить ПРЕДОСТАВИТЬ .

Наконец, введите \q , чтобы выйти из оболочки, если хотите.

Если вы хотите узнать больше о psql , вы можете взглянуть на Документы Postgres .

Создайте сервер ресурсов загрузки Spring

Клонируйте начальный проект из репозитория GitHub и проверьте ветвь start :

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

Стартовый проект – это проект весенней загрузки с чистого листа, в котором уже есть небольшая конфигурация, специфичная для Postgres. Если вы посмотрите в файле build.gradle , вы увидите зависимость соединителя JPA PostgreSQL. Вы также заметите файл src/основные/ресурсы/спящий режим.свойства чья единственная цель – избавиться от раздражающего предупреждения/ошибки, которые на самом деле не имеют для нас значения. Файл 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 определяет поведение режима гибернации при загрузке. Варианты следующие:

  • проверка: проверяет схему, но не вносит никаких изменений
  • обновление: обновляет схему
  • создать: создает схему, уничтожая все предыдущие данные
  • создать-удалить: как создать, но также удаляет схему при закрытии сеанса (полезно для тестирования)

Вы используете создать . При каждом запуске программы создается новая база данных, начиная со свежих таблиц и данных.

платформа базы данных на самом деле не нужна. Весенние данные/режим гибернации могут автоматически определять платформу. Однако без этого свойства, если вы запустите приложение, не запустив сервер Postgres, вы получите довольно бесполезную ошибку о том, что вы не добавили это свойство конфигурации вместо того, чтобы вам сказали запустить ваш сервер. Это происходит потому, что Hibernate не может автоматически определить платформу базы данных, поэтому жалуется на это, прежде чем жаловаться на то, что на самом деле не работает сервер.

Запустите приложение с помощью ./gradlew Загрузочный . Вы должны увидеть что-то вроде этого:

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 и JPA

Домен или модель – это программное представление данных, которые вы будете хранить. Магия Spring Data и JPA заключается в том, что Spring может взять класс Java и превратить его в таблицу базы данных для вас. Он даже автоматически создаст необходимые методы загрузки и сохранения. Самое приятное то, что это (более или менее) независимая база данных.

Вы используете PostgreSQL в этом руководстве, и вы могли бы довольно легко переключить его на MySQL, если бы захотели, просто изменив зависимость в файле build.gradle . И, конечно же, создание базы данных MySQL и обновление необходимых свойств в файле application.yml . Это очень полезно для тестирования, разработки и долгосрочного обслуживания.

Продолжайте читать, чтобы узнать, как разработать простой сервер для хранения типов байдарок.

Создайте файл Java в com.okta.spring boot jpa пакете с именем 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;
}

В этом проекте используется Ломбок , чтобы избежать необходимости кодировать кучу церемониальных геттеров, сеттеров и тому подобного. Вы можете проверить их документы или, более конкретно, аннотацию @Data , которую вы используете .

Аннотация @Entity сообщает Spring, что этот класс является классом модели и должен быть преобразован в таблицу базы данных.

Большинство свойств могут быть сопоставлены автоматически. Однако свойство id украшено парой примечаний, потому что нам нужно сообщить JPA, что это поле идентификатора и что оно должно быть автоматически сгенерировано.

Реализовать хранилище CRUD с JPA Spring Data

С определенным классом домена Spring знает достаточно для создания таблицы базы данных, но у него нет определенных методов контроллера. Для данных нет ни вывода, ни ввода. Весна делает добавление сервера ресурсов тривиальным. На самом деле, это настолько тривиально, что вы, вероятно, не поверите.

В упаковке В упаковке , создайте интерфейс под названием 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 {
}

Вот и все!

Теперь вы можете создавать, читать, обновлять и удалять байдарки с сервера ресурсов. Через секунду вы сделаете именно это, но прежде чем вы это сделаете, внесите еще одно изменение.

Добавьте следующий метод init() в класс Spring Boot Jpa-приложения :

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

}

Этот метод будет запущен при запуске приложения. Он загружает некоторые образцы данных на сервер ресурсов просто для того, чтобы вам было на что посмотреть в следующем разделе.

Протестируйте Свой Сервер ресурсов Spring Boot

HTTPie – отличная утилита командной строки, которая упрощает выполнение запросов к серверу ресурсов. Если у вас не установлен HTTPie, установите его с помощью brew install httpie . Или зайдите на их веб-сайт и сделайте так, чтобы это произошло. Или просто следуйте за мной.

Убедитесь, что ваше приложение Spring Boot запущено. Если это не так, запустите его с помощью ./gradlew Загрузочный .

Запустите запрос 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. Вы также можете добавить новый каяк, используя СООБЩЕНИЕ.

Команда:

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/байдарки/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:create в файле application.yml .

Настройка Аутентификации

Okta является поставщиком удостоверений, аутентификации и авторизации программного обеспечения как услуги. Хотя я определенно работал над проектами, в которых передача всего на аутсорсинг поставщикам SaaS создавала больше проблем, чем обещала решить, аутентификация и авторизация – это место, где эта модель имеет полный смысл. Онлайн-безопасность – это сложно. Обнаружены уязвимости, и серверы должны быть быстро обновлены. Стандарты меняются, и код нуждается в модификации. Все эти изменения потенциально могут создать новые уязвимости. Позволяя Okta обеспечивать безопасность, вы можете беспокоиться о том, что делает ваше приложение уникальным.

Чтобы показать вам, как легко это настроить, вы собираетесь интегрировать Okta OAuth и добавить аутентификацию на основе токенов на сервер ресурсов. Если вы еще этого не сделали, перейдите на developer.okta.com и подпишитесь на бесплатную учетную запись. Как только у вас появится учетная запись, откройте панель мониторинга разработчика и создайте приложение OpenID Connect (OIDC), нажав на пункт Приложение в верхнем меню, а затем на кнопку Добавить приложение .

Выберите Одностраничное приложение .

Настройки приложения по умолчанию отличные, за исключением того, что вам нужно добавить URI перенаправления входа : а . Вы собираетесь использовать это через мгновение, чтобы получить тестовый токен.

Кроме того, обратите внимание на свой Идентификатор клиента , так как он вам понадобится через мгновение.

Настройте Сервер ресурсов загрузки Spring для аутентификации по маркерам

Okta сделала добавление аутентификации по токенам в Spring Boot очень простым. У них есть проект под названием Okta Spring Boot Starter ( ознакомьтесь с проектом GitHub ), который упрощает весь процесс до нескольких простых шагов.

Добавьте пару зависимостей в свой файл 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 (это устраняет конфликт зависимостей ведения журнала обратной связи).

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

Затем вам нужно добавить некоторую конфигурацию в ваш файл application.yml , заменив {ваш идентификатор клиента} идентификатором клиента из вашего приложения OIDC Okta и {ваш домен домена} вашим URL-адресом Okta. Что-то вроде https://dev-123456.oktapreview.com .

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

Наконец, вам нужно добавить аннотацию @enableresourceserver в свой класс Springbootapplication .

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

Остановите сервер загрузки Spring и перезапустите его, используя: ./gradlew Загрузочный .

Из командной строки запустите простой запрос 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 .

Авторизовать URL : https://{youroktaurl}/oauth2/по умолчанию/v1/авторизовать , с {Youroktaurl} заменен вашим фактическим URL-адресом Oktapreview.

Перенаправление URI : не изменяться. Это значение, которое вы добавили в свое приложение OIDC выше.

Идентификатор клиента : из только что созданного приложения OIDC.

Область действия : электронная почта профиля openid .

Состояние : любое значение, которое вы хотите передать через процесс перенаправления OAuth. Я установил его в {} .

Nonce : можно оставить в покое. Nonce означает “номер, используемый один раз” и является простой мерой безопасности, используемой для предотвращения многократного использования одного и того же запроса.

Тип ответа : токен .

Режим ответа : форм_пост .

Нажмите Отправить запрос . Если вы не вошли в систему developer.okta.com, затем вам потребуется войти в систему. Если вы (что вполне вероятно) уже вошли в систему, то токен будет сгенерирован для вашего удостоверения пользователя, вошедшего в систему.

Используйте маркер доступа

Вы используете токен, включив Авторизацию заголовок запроса типа Предъявитель .

Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3VJSzBBYUl3NkU4SDJfNVJr...

Чтобы сделать запрос с помощью HTTP ie:

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

Добавить групповую авторизацию

До сих пор схема авторизации была довольно бинарной. Содержит ли запрос действительный токен или нет. Теперь вы собираетесь добавить групповую аутентификацию. Обратите внимание, что, несмотря на то, что иногда они используются взаимозаменяемо на сайтах с дурной репутацией, роли и группы – это не одно и то же, и это разные способы реализации авторизации.

роль – это набор разрешений, которые пользователь может наследовать. группа – это набор пользователей, которым назначен набор стандартных разрешений. Однако в области токенов и того, как вы используете Spring Security с JPA, реализация точно такая же; они оба передаются из приложения OAuth OIDC в виде строки “полномочия” в Spring, поэтому на данный момент они по существу взаимозаменяемы. Разница будет заключаться в том, что защищено и как они определены.

Чтобы использовать групповую авторизацию с помощью Okta, вам необходимо добавить требование “группы” к вашему маркеру доступа. Создайте Администраторскую группу ( Пользователи > Группы > Добавьте группу ) и добавьте в нее своего пользователя. Вы можете использовать учетную запись, с которой вы зарегистрировались, или создать нового пользователя ( Пользователи > Добавить Человека ). Перейдите к API > Серверы авторизации , перейдите на вкладку Серверы авторизации и измените вкладку по умолчанию. Перейдите на вкладку Утверждения и Добавить утверждение . Назовите его “группы” и включите его в маркер доступа. Установите тип значения “Группы” и установите фильтр в виде регулярного выражения . * .

Создайте новый маркер доступа с помощью Отладчика OIDC . Взгляните на свой декодированный токен, перейдя в jsonwebtoken.ввод и ввод сгенерированного вами токена доступа.

Полезная нагрузка будет выглядеть примерно так:

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

Утверждение groups содержит группы, к которым назначен пользователь. Пользователь, которого вы используете для входа в developer.okta.com веб-сайт также будет членом как группы “Все”, так и группы “Администратор”.

Чтобы заставить Spring Boot и сервер ресурсов хорошо работать с групповой авторизацией, вам нужно внести несколько изменений в код.

Сначала добавьте новый класс Java в com.okta.spring boot jpa пакет под названием Конфигурация безопасности .

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 в репозиторий Kayak , например:

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

@RepositoryRestResource  
@PreAuthorize("hasAuthority('Admin')")  
public interface KayakRepository extends CrudRepository {  
}

Наконец, в приложении Spring Boot Jpa , удалите инициализацию Запуска приложения (репозиторий Kayak Repository) метод (или просто закомментируйте @Bean аннотацию). Если вы пропустите этот шаг, сборка завершится со следующей ошибкой:

 AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

Аннотация @PreAuthorize фактически блокирует метод init() от создания загрузочных данных программно, поскольку ни один пользователь не вошел в систему. Таким образом, при запуске метода он выдает ошибку.

Обратите внимание, что вы используете имеет полномочия() в @Предварительная авторизация аннотация и не |/роль() . Разница в том, что hasRole() ожидает, что группы или роли будут во ВСЕХ шапках и будут иметь префикс ROLE_ . Это, конечно, можно настроить, но имеет полномочия() поставляется без этого багажа и просто проверяет любое утверждение, которое вы определили как okta.oauth2.роли-утверждение в вашем приложении.yml .

Протестируйте пользователя-администратора в своем приложении Spring Boot

Перезапустите приложение Spring Boot (начните с ./gradlew Загрузочный ).

Попробуйте выполнить запрос GET без проверки подлинности: 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 пуст.

СОВЕТ: в дальнейшем, если вы не хотите копировать и вставлять всю огромную строку токенов, вы можете сохранить ее в переменной оболочки и повторно использовать ее следующим образом:

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

Создайте пользователя, не являющегося администратором

Чтобы продемонстрировать групповую авторизацию, вам необходимо создать нового пользователя в Okta, который не является администратором. Перейдите к developer.okta.com приборная панель.

В верхнем меню выберите Пользователи и Люди .

Нажмите кнопку Добавить пользователя .

Дайте пользователю Имя , Фамилия , и Имя пользователя (который также будет Основным электронным письмом ). Значения не имеют значения, и вам не нужно будет проверять электронную почту. Вам просто нужно знать адрес электронной почты/имя пользователя и пароль, чтобы вы могли войти в Okta через минуту.

Пароль : измените раскрывающийся список на , установленный администратором .

Назначьте пользователю пароль.

Нажмите Сохранить .

Вы только что создали пользователя, который НЕ является членом группы Admin , но является членом группы по умолчанию Все .

Проверка авторизации на основе групп в приложении Spring Boot

Выйдите из своей панели управления разработчика Okta.

Вернитесь к отладчику OIDC и сгенерируйте новый токен.

На этот раз войдите в систему как новый пользователь, не являющийся администратором. Вам будет предложено выбрать секретный вопрос, после чего вы будете перенаправлены на https://oidcdebugger.com/debug страница, на которой можно скопировать ваш токен.

Если хотите, вы можете перейти в jsonwebtoken.ввод и расшифруйте свой новый токен. В полезной нагрузке sub утверждение покажет адрес электронной почты/имя пользователя пользователя, а группы утверждение покажет только Все группу.

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

Если вы используете новый токен для отправки запроса на /байдарках конечная точка, вы получите 403/Отказано в доступе.

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


HTTP/1.1 403
...

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

Чтобы продемонстрировать реальную силу @предварительной авторизации аннотации, создайте ограничение безопасности на уровне метода. Измените класс Репозитория Kayak на следующий:

@RepositoryRestResource  
public interface KayakRepository extends CrudRepository {  

    @PreAuthorize("hasAuthority('Admin')")  
     S save(S entity);  

}

Это ограничивает только метод save() для членов группы администраторов. Остальная часть хранилища будет ограничена, просто требуя аутентификации, но без членства в определенной группе.

Перезапустите сервер загрузки Spring. Выполните тот же запрос еще раз.

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-сообщению здесь.

Однако, если вы используете токен, сгенерированный из вашей исходной учетной записи администратора, он будет работать.

записка: Возможно, срок действия вашего токена истечет, и вам придется выйти из 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 extends Repository {
   S save(S entity);
   Iterable saveAll(Iterable entities);
  Optional findById(ID id);
  boolean existsById(ID id);
  Iterable findAll();
  Iterable findAllById(Iterable ids);
  long count();
  void deleteById(ID id);
  void delete(T entity);
  void deleteAll(Iterable entities);
  void deleteAll();
}

И это все! Довольно круто, правда? В этом руководстве вы настроили базу данных PostgreSQL, создали сервер ресурсов загрузки Spring, который использовал данные Spring и JPA для сохранения модели данных, а затем превратили эту модель данных в API REST с потрясающе малым количеством кода. Кроме того, вы использовали Okta для добавления аутентификации OIDC и авторизации OAuth 2.0 в свое серверное приложение. И, наконец, вы внедрили простую схему авторизации на основе групп.

Если вы хотите ознакомиться с этим полным проектом, вы можете найти репозиторий на GitHub по адресу @xdadevelopers/okta-spring-boot-jpa-пример .

Следите за нашим следующим сообщением в этой серии, которое будет посвящено использованию базы данных NoSQL (MongoDB) с Spring Web Flux.

Узнайте больше о Spring Boot, безопасности Spring и Безопасная Аутентификация

Если вы хотите узнать больше о Spring Boot, Spring Security или безопасности современных приложений, ознакомьтесь с любым из этих замечательных учебных пособий:

Если вы хотите погрузиться глубже, взгляните на проект Okta Spring Boot Starter GitHub/|.

Это отличный справочник по данным Spring и обеспечению безопасности проектов Spring Boot: https://docs.spring.io/spring-data/rest/docs/current/reference/html/ .

У Влада Михальчи есть отличный учебник под названием 9 высокопроизводительных советов при использовании PostgreSQL с JPA и гибернацией .

В Baeldung есть полезный учебник по методам защиты в проектах Spring Data/Spring Boot: https://www.baeldung.com/spring-security-method-security .

Наконец, если вам нужна дополнительная помощь с PostgreSQL в Mac OS X, см. этот кодементор.учебник по вводу-выводу .

Если у вас есть какие-либо вопросы по поводу этого поста, пожалуйста, добавьте комментарий ниже. Для получения более потрясающего контента следуйте @oktadev в Twitter, как мы на Facebook или подпишитесь на наш канал YouTube .

Оригинал: “https://dev.to/oktadev/build-a-basic-app-with-spring-boot-and-jpa-using-postgresql-ke9”