Beveiliging van uw toepassing gaat verder dan alleen het toewijzen of afwezigheid van toegang op de oppervlakte. Als ontwikkelaar moet u fine-grained authorization
(FGA) implementeren om toegangsrechten op een meer gedetailleerde, granuliere schaal te beheren.
FGA laat u toe om gedetailleerde toegangscontroles in te stellen die specificeren wie wat kan doen en onder welke voorwaarden.
In deze handleiding leert u hoe u fine-grained authorization
in Java en Spring Boot kunt implementeren met behulp van Permit.io.
Hier is de broncode (denk eraan om er een ster ⭐ aan toe te voegen).
Ik hoop dat u mijn vorige blog over het bouwen van een aangepaste video conferentie app met Stream en Next.js genoten heeft. Deze blogs zijn een reflectie van mijn reis in het maken van DevTools Academy, een platform dat is ontworpen om ontwikkelaars te helpen ontdekken wat er bijzonderleuke ontwikkelingsgereedschappen zijn.
Deze handleiding is een andere poging om u aan een uitstekend ontwikkelingsgereedschap voor ontwikkelaars te introduceren dat ik recentelijk heb ontdekt.
Inhoudsopgave:
Wat is Permit?
Permit.io is een volledige stack, draadloze toepassingsniveau autorisatiesolutie die het mogelijk maakt binnen minuten een
veilige
,flexibele
,autorisatie
laag te implementeren, zodat u zich kunt richten op wat eromgaat.
Voorwaarden
Om dit handleiding volledig te kunnen begrijpen, moet u een basisbegrip van Java
en Spring Boot
hebben. U bent ook nodig aan de volgende voorwaarden:
-
Permit.io: Een ontwikkelingshulpmiddel dat het implementeren van FGA simplificeert.
-
Spring Boot Starter Web: Bevat essentiële componenten voor het bouwen van webapplicaties, inclusief RESTful API’s.
-
Gradle: Een bouwgereedschap voor het beheren van afhankelijkheden.
-
JDK 11 of later: De versie van de Java Development Kit die nodig is om uw Spring Boot-app te compileren en te draaien.
-
Postman of cURL: Tools voor het testen van uw
API
-eindpunten.
Wat is FGA (Fine-Grained Authorization)?
FGA (Fine-Grained Authorization) biedt toegangscontrole tot resources door te bepalen wie ze kan bereiken, in welke mate en onder specifieke voorwaarden.
Contrairement aan ruwmagnetische toegangsautorisatie (die toegang handhaaft op basis van categorieën als gebruikersrollen
zoals “admin
” of “gebruiker
“), brengt fine-grained autorisatie u de flexibiliteit om toegang op een verfijnde niveau te definiëren, voor specifieke resources of acties en zelfs eigenschappen.
In Fine Grained Authorization
bestaan er 3 typen policy modellen voor het beheren van autorisatie; Rolgebaseerd Toegangsbeheer (RBAC), Eigenschapgebaseerd Toegangsbeheer (ABAC), en Relatiegebaseerd Toegangsbeheer (ReBAC).
Laten we kijken, naar elk van deze aanpakken en zien hoe u ze in uw toepassing kunt implementeren.
Rolgebaseerd Toegangsbeheer (RBAC)
RBAC is een veiligheidsoverweging die gegevenstoegang beheert op basis van de rollen van gebruikers binnen een organisatie. Deze model vereenvoudigt toegangsrechten door gebruikers in rollen te organiseren en toegangscontrole te beheren volgens deze gedefinieerde rollen.
Belangrijke Concepten in RBAC:
Gebruikers: Mensen die het systeem gebruiken, zoals werknemers of klanten.
Rollen: Een verzameling toegangsrechten of -privileges toegewezen aan een groep gebruikers op basis van hun verantwoordelijkheden of taken, zoals admin, manager of klant.
Rechten: De rechten die aan gebruikers worden toegekend voor het interactie met resources, zoals lezen, schrijven of verwijderen.
Eigenschapgebaseerd Toegangsbeheer (ABAC)
ABAC is een flexibel en aanpasbaar toegangsbeheersingsmodel dat bepaalt wie toegang tot resources heeft of niet, op basis van attributen, zoals gebruikersgegevens. Het ABAC-model laat u toe om op basis van gebruikersattributen gekleineerd toegangsrecht in te stellen.
Belangrijke concepten in ABAC:
Attributen: Eigenschappen of properties die worden gebruikt om toegangsdecisionen te nemen. Attributen zijn typisch onderverdeeld in:
-
Gebruikersattributen: Informatie over de gebruiker (bijvoorbeeld rol, afdeling, functietitel, leeftijd, enzovoort).
-
Resourceattributen: Eigenschappen van de resource (bijvoorbeeld bestandstype, data classificatie niveau, creatiedatum, eigenaar).
-
Actieattributen: De actie die de gebruiker probeert uit te voeren (bijvoorbeeld lezen, schrijven, verwijderen, goedkeuren).
-
Omgevingsattributen: Contextuele informatie over het toegangsverzoek (bijvoorbeeld tijd van de dag, locatie, apparaattype, IP-adres).
Relatiegebaseerd Toegangsbeheer (ReBAC)
ReBAC is een toegangsbeheersysteem dat toestemmingen voor toegang tot resources verleent op basis van de relatie tussen entiteiten binnen een systeem. Het aanpakken plaatst de focus op het definiëren en beheren van toegangsbeheer door de manier waarop gebruikers tot resources en andere entiteiten zoals organisaties of groepen relaties hebben.
Belangrijke Concepten van ReBAC:
Entiteiten: Gebruikers, resources (zoals bestanden en documenten) en andere entiteiten, zoals groepen of organisatorische eenheden.
Relaties: De verbindingen die de relatie tussen twee entiteiten specificeren. Een gebruiker kan bijvoorbeeld de “eigenaar” zijn van een document of een “lid” zijn van een team.
Beleid: Regels die relaties gebruiken om toegangsrechten te bepalen. Een gebruiker kan toegang krijgen tot een resource of een actie op die resource uitvoeren als ze een bepaalde relatie met het hebben.
Hoe U Fijne-Graad Autorisatie Implementeert
Nu u een basisbegrip van RBAC
, ABAC
en ReBAC
hebt, zie hoe we deze modellen kunnen implementeren in een e-commerce-app.
Implementeren van Rolgebaseerd Toegangsbeheer
Stap 1: Ga naar Permit.io en maak een account en uw werkruimte aan.
Standaard zou je een project moeten zien dat twee omgevingen omvat: Development
en Production
.
Stap 2: Maak een bron genaamd Products. Om de bron te maken, open je het tabblad Policy in de linker zijbalk en vervolgens het tabblad Resources bovenaan. Klik daarna op de knop Create a Resource en maak dan een bron genaamd Products met acties read
, create
, update
en delete
.
Stap 3: Maak een andere bron genaamd Reviews met acties read
, create
, update
en delete
.
Stap 4: Open het tabblad Policy Editor. Je zult zien dat er 3 rollen zijn aangemaakt met de namen admin
, editor
en viewer
.
-
Rol admin heeft toestemming om een product of een review te
create
,delete
,read
ofupdate
. -
Rol
editor
heeft toestemming om eenproduct
of eenreview
tecreate
,read
ofupdate
maar niet tedelete
. -
De rol `viewer` heeft toestemming om een product of een `review` `create` en `read` te doen, maar niet `delete` of `update`.
Implementeren van Attribut gebaseerde Toegangs Controle
Stap 1: Open de Resources tab, klik vervolgens op de Add Attributes knop.
-
Voeg een attribuut toe genaamd vendor
-
Voeg een attribuut toe genaamd de customer
Stap 2: Open de ABAC Rules tab, maak vervolgens een nieuwe ABAC Resource Set aan genaamd Own Products die afhankelijk is van het Products resource. Vervolgens voeg u een voorwaarde toe die alleen toestemming geeft aan de gebruiker die een product op basis van het vendor attribuut heeft aangemaakt.
Stap 3: Maak nog een ABAC Resource Set aan genaamd Own Reviews die afhankelijk is van het Reviews resource.
Implementeren van Relatie gebaseerde Toegangs Controle
Stap 1: Open de Resources tab en bewerkt u het Products resource. Voeg de rol vendor
toe in de ReBAC
opties sectie. Stel vervolgens producten in als bovenliggende reviews in de relaties sectie.
Stap 2: Wijzig de Reviews resource door het toevoegen van de rol klant in de ReBAC
opties sectie, zoals getoond hieronder:
Stap 3: Ga naar de Policy
Editor
tab en voeg toe:
-
rol
verkoper
toestemming om eigen producten bij te werken en te verwijderen. -
rol
klant
toestemming om eigen beoordelingen op producten bij te werken en te verwijderen.
Hoe FGA in Java en SpringBoot te implementeren
Nu we RBAC
, ABAC
en ReBAC
beleid in de Permit.io webinterface hebben gedefinieerd, leren we hoe we ze kunnen afdwingen in een E-Commerce Management System applicatie met behulp van de Permit.io API.
Er komt veel code, dus zorg ervoor dat je de uitgebreide commentaarstrips die ik over elk codeblok heb achtergelaten leest. Deze zullen je helpen beter te begrijpen wat er gebeurt in dit code.
Stap 1: E-commerce Applicatie Setup
Om de e-commerce applicatie op te zetten en de broncode te clonen via git.
git clone https://github.com/tyaga001/java-spring-fine-grained-auth.git
Permit pakket SDK installeren
Om de Permit pakket SDK te installeren, voeg je het SDK onder het afhankelijkheden blok in het build.gradle
bestand toe.
## Dependencies
To set up the necessary dependencies for your Spring Boot project, include the following in your `build.gradle` file:
```groovy
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// Voeg deze regel toe om de Permit.io Java SDK in uw project te installeren
implementation 'io.permit:permit-sdk-java:2.0.0'
}
Initialiseer de Permit SDK
U kunt de Permit SDK
Client initialiseren door het volgende codeblok te gebruiken:
package com.boostmytool.store.config;
import io.permit.sdk.Permit;
import io.permit.sdk.PermitConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // Markeert deze klasse als een configuratieklasse voor Spring IoC
public class PermitClientConfig {
@Value("${permit.api-key}") // Injecteer de Permit API-sleutel uit de toepassingseigenschappen
private String apiKey;
@Value("${permit.pdp-url}") // Injecteer de Permit PDP (Policy Decision Point) URL uit de toepassingseigenschappen
private String pdpUrl;
/**
* Maakt een Permit-clientbean met een aangepaste configuratie
* @return Permit-clientinstantie
*/
@Bean
public Permit permit() {
return new Permit(
new PermitConfig.Builder(apiKey) // Initialiseer PermitConfig met API-sleutel
.withPdpAddress(pdpUrl) // Stel de PDP-adres in
.withDebugMode(true) // Schakel debugmodus in voor gedetailleerde logging
.build() // Bouw het PermitConfig-object
);
}
}
Gebruikerssynchroniseren met de SDK
Om machtigingen te handhaven, moet u eerst een gebruiker met Permit synchroniseren en vervolgens een rol aan hen toewijzen.
In het volgende codeblok biedt de UserService klasse methodes voor gebruikerslogin, registratie, roltoewijzing en autorisatie, met exception handling voor mogelijke fouten bij het interactie met de Permit API.
package com.boostmytool.store.service;
import com.boostmytool.store.exception.ForbiddenAccessException;
import com.boostmytool.store.exception.UnauthorizedException;
import io.permit.sdk.Permit;
import io.permit.sdk.api.PermitApiError;
import io.permit.sdk.api.PermitContextError;
import io.permit.sdk.enforcement.Resource;
import io.permit.sdk.enforcement.User;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service // Markeert deze klasse als een Spring dienst, waardoor hij een kandidaat is voor component扫描
public class UserService {
private final Permit permit;
// Constructor injectie voor het Permit SDK
public UserService(Permit permit) {
this.permit = permit;
}
/**
* Simuleert een gebruikerlogin door het maken en teruggeven van een Permit Gebruiker object.
*
* @param key Het unieke sleutel van de gebruiker
* @return Gebruiker object
*/
public Object login(String key) {
return new User.Builder(key).build();
}
/**
* Handelt gebruikersregistratie af door het maken en synchroniseren van een nieuw Permit Gebruiker.
*
* @param key Het unieke sleutel van de gebruiker
* @return Gemaakt en gesynchroniseerd Gebruiker object
*/
public User signup(String key) {
var user = new User.Builder(key).build();
try {
permit.api.users.sync(user); // Synchroniseert de nieuwe gebruiker met de Permit dienst
} catch (PermitContextError | PermitApiError | IOException e) {
throw new RuntimeException("Failed to create user", e); // Handelt uitzonderingen af tijdens de creatie van de gebruiker
}
return user;
}
/**
* Toewijst een rol aan de gebruiker binnen de "default" omgeving.
*
* @param user Het Gebruiker object waar de rol aan moet worden toegewezen
* @param role Het toegewezen rol
*/
public void assignRole(User user, String role) {
try {
permit.api.users.assignRole(user.getKey(), role, "default"); // Toewijst rol in de "default" omgeving
} catch (PermitApiError | PermitContextError | IOException e) {
throw new RuntimeException("Failed to assign role to user", e); // Handelt uitzonderingen af tijdens het toewijzen van de rol
}
}
/**
* Controleert of de gebruiker gemachtigd is om een specifieke actie op een resource uit te voeren.
*
* @param user Het Gebruiker object dat toestemming vraagt
* @param action De moeten worden geautoriseerde actie
* @param resource Het door de actie wordt aangetast resourcetype
* @throws UnauthorizedException Indien de gebruiker niet ingelogd is
* @throws ForbiddenAccessException Indien de toegang geweigerd wordt
*/
public void authorize(User user, String action, Resource resource) {
if (user == null) {
throw new UnauthorizedException("Not logged in"); // Gooit een uitzondering als de gebruiker niet ingelogd is
}
try {
var permitted = permit.check(user, action, resource); // Voert authorisatiescheck uit
if (!permitted) {
throw new ForbiddenAccessException("Access denied"); // Gooit een uitzondering als toegang geweigerd wordt
}
} catch (PermitApiError | IOException e) {
throw new RuntimeException("Failed to authorize user", e); // Handelt uitzonderingen af tijdens de authorisatie
}
}
}
In het onderstaande codeblok exposeert de UserController-klasse REST API-eindpunten voor gebruikersregistratie en roltoewijzing. Het werkt samen met de UserService-klasse om de bedrijfslogica van gebruikersoperaties af te handelen en levert een geschikte HTTP-reactie.
package com.boostmytool.store.controllers;
import com.boostmytool.store.exception.UnauthorizedException;
import com.boostmytool.store.service.UserService;
import io.permit.sdk.enforcement.User;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // Geeft aan dat deze klasse HTTP-verzoeken afhandelt en JSON-reacties teruggeeft
@RequestMapping("/api/users") // Basis URL-pad voor alle gebruikersgerelateerde operaties
public class UserController {
private final UserService userService;
// Constructorinjectie van UserService, die de bedrijfslogica voor gebruikersoperaties bevat
public UserController(UserService userService) {
this.userService = userService;
}
/**
* Handelt gebruikersregistratieverzoeken af.
* Eindpunt: POST /api/users/signup
*
* @param key Unieke sleutel voor de nieuwe gebruiker
* @return Gecreëerd Gebruikersobject
*/
@PostMapping("/signup")
public User signup(@RequestBody String key) {
return userService.signup(key); // Roep de signupmethode in UserService aan om een nieuwe gebruiker te maken
}
/**
* Handelt het toewijzen van een rol aan de ingelogde gebruiker af.
* Eindpunt: POST /api/users/assign-role
*
* @param request HTTP-verzoek, gebruikt om de huidige gebruiker op te halen
* @param role Rol die aan de huidige gebruiker toegekend moet worden
*/
@PostMapping("/assign-role")
public void assignRole(HttpServletRequest request, @RequestBody String role) {
// Haalt de huidige gebruiker uit de verzoekattributen op
User currentUser = (User) request.getAttribute("user");
// Telt uit als de gebruiker niet is ingelogd
if (currentUser == null) {
throw new UnauthorizedException("Not logged in");
}
// Toewijst de opgegeven rol aan de huidige gebruiker
userService.assignRole(currentUser, role);
}
}
Aanmaken van RBAC, ABAC en ReBAC-beleidsenforcementpoint
In het onderstaande codebestand beheert de ProductService klasse CRUD-operaties voor producten en recensies, met behandeling van machtigingen en rollen via de Permit API.
Elke operatie omvat gebruikers autorisatie
controles, met geschikte uitzonderingsbehandeling voor Permit API fouten en gegevens niet gevonden scenario’s.
package com.boostmytool.store.service;
import com.boostmytool.store.exception.ResourceNotFoundException;
import com.boostmytool.store.model.Product;
import com.boostmytool.store.model.Review;
import io.permit.sdk.Permit;
import io.permit.sdk.api.PermitApiError;
import io.permit.sdk.api.PermitContextError;
import io.permit.sdk.enforcement.Resource;
import io.permit.sdk.enforcement.User;
import io.permit.sdk.openapi.models.RelationshipTupleCreate;
import io.permit.sdk.openapi.models.ResourceInstanceCreate;
import io.permit.sdk.openapi.models.RoleAssignmentCreate;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Service // Markeert deze klasse als een Spring-service
public class ProductService {
private final List<Product> products = new ArrayList<>(); // In-memory lijst om producten op te slaan
private final AtomicInteger productIdCounter = new AtomicInteger(); // Teller om unieke product-ID's te genereren
private final AtomicInteger reviewIdCounter = new AtomicInteger(); // Teller om unieke review-ID's te genereren
// Builders voor Permit-broninstanties (product en review)
private final Resource.Builder productResourceBuilder = new Resource.Builder("product");
private final Resource.Builder reviewResourceBuilder = new Resource.Builder("review");
private final UserService userService; // Service voor het afhandelen van gebruikersgerelateerde operaties
private final Permit permit; // Permit SDK-instantie voor het afhandelen van autorisatie en bronbeheer
// Constructor voor het injecteren van afhankelijkheden
public ProductService(UserService userService, Permit permit) {
this.userService = userService;
this.permit = permit;
}
// Methode om een gebruiker te autoriseren voor een bepaalde actie op een bron
private void authorize(User user, String action, Resource resource) {
userService.authorize(user, action, resource);
}
// Autoriseert een gebruiker om een actie uit te voeren op een specifiek product
private void authorize(User user, String action, Product product) {
var attributes = new HashMap<String, Object>();
attributes.put("vendor", product.getVendor()); // Voeg verkoper-attribuut toe aan het product
userService.authorize(user, action, productResourceBuilder.withKey(product.getId().toString()).withAttributes(attributes).build());
}
// Autoriseert een gebruiker om een actie uit te voeren op een specifieke review
private void authorize(User user, String action, Review review) {
var attributes = new HashMap<String, Object>();
attributes.put("customer", review.getCustomer()); // Voeg klant-attribuut toe aan de review
userService.authorize(user, action, reviewResourceBuilder.withKey(review.getId().toString()).withAttributes(attributes).build());
}
// Haalt een product op aan de hand van zijn ID, gooit een uitzondering als het niet wordt gevonden
private Product getProductById(int id) {
return products.stream().filter(product -> product.getId().equals(id))
.findFirst().orElseThrow(() -> new ResourceNotFoundException("Product with id " + id + " not found"));
}
// Haalt alle producten op, controleert of de gebruiker geautoriseerd is om producten te "lezen"
public List<Product> getAllProducts(User user) {
authorize(user, "read", productResourceBuilder.build()); // Gebruiker moet "lees"-rechten hebben
return new ArrayList<>(products); // Geef een kopie van de productenlijst terug
}
// Haalt een product op aan de hand van zijn ID, controleert of de gebruiker geautoriseerd is om het product te "lezen"
public Product getProduct(User user, int id) {
authorize(user, "read", productResourceBuilder.build());
return getProductById(id);
}
// Voegt een nieuw product toe, autoriseert de gebruiker en maakt broninstanties en roltoewijzingen aan in Permit
public Product addProduct(User user, String content) {
authorize(user, "create", productResourceBuilder.build()); // Controleer of de gebruiker een product kan aanmaken
Product product = new Product(productIdCounter.incrementAndGet(), user.getKey(), content); // Maak nieuw product aan
try {
// Maak broninstantie aan in Permit en wijs "verkoper"-rol toe aan de gebruiker voor dit product
permit.api.resourceInstances.create(new ResourceInstanceCreate(product.getId().toString(), "product").withTenant("default"));
permit.api.roleAssignments.assign(new RoleAssignmentCreate("vendor", user.getKey()).withResourceInstance("product:" + product.getId()).withTenant("default"));
} catch (IOException | PermitApiError | PermitContextError e) {
throw new RuntimeException("Failed to create resource instance or role assignment: " + e.getMessage());
}
products.add(product); // Voeg product toe aan in-memory lijst
return product;
}
// Werkt de inhoud van een product bij, controleert of de gebruiker geautoriseerd is om het product te "updaten"
public Product updateProduct(User user, int id, String content) {
Product product = getProductById(id); // Haal het product op aan de hand van zijn ID
authorize(user, "update", product); // Controleer of de gebruiker het product kan bijwerken
product.setContent(content); // Werk productinhoud bij
return product;
}
// Verwijdert een product, controleert of de gebruiker geautoriseerd is om het product te "verwijderen"
public void deleteProduct(User user, int id) {
boolean isDeleted = products.removeIf(product -> {
if (product.getId().equals(id)) {
authorize(user, "delete", product); // Controleer of de gebruiker het product kan verwijderen
return true;
} else {
return false;
}
});
if (!isDeleted) {
throw new ResourceNotFoundException("Product with id " + id + " not found");
}
try {
permit.api.resourceInstances.delete("product:" + id); // Verwijder productbroninstantie uit Permit
} catch (IOException | PermitApiError | PermitContextError e) {
throw new RuntimeException(e);
}
}
// Voegt een review toe aan een product, maakt een broninstantie en relatie aan in Permit
public Review addReview(User user, int productId, String content) {
authorize(user, "create", reviewResourceBuilder.build()); // Controleer of de gebruiker een review kan aanmaken
Product product = getProductById(productId); // Haal het product op aan de hand van zijn ID
Review review = new Review(reviewIdCounter.incrementAndGet(), user.getKey(), content); // Maak nieuwe review aan
try {
// Maak een broninstantie aan voor de review en stel de relatie met het product in
permit.api.resourceInstances.create(new ResourceInstanceCreate(review.getId().toString(), "review").withTenant("default"));
permit.api.relationshipTuples.create(new RelationshipTupleCreate("product:" + productId, "parent", "review:" + review.getId()));
} catch (IOException | PermitApiError | PermitContextError e) {
throw new RuntimeException(e);
}
product.addReview(review); // Voeg de review toe aan het product
return review;
}
// Werkt de inhoud van een review bij, controleert of de gebruiker geautoriseerd is om de review te "updaten"
public Review updateReview(User user, int productId, int reviewId, String content) {
Product product = getProductById(productId); // Haal het product op aan de hand van zijn ID
Review review = product.getReviews().stream().filter(c -> c.getId().equals(reviewId))
.findFirst().orElseThrow(() -> new ResourceNotFoundException("Review with id " + reviewId + " not found"));
authorize(user, "update", review); // Controleer of de gebruiker de review kan bijwerken
review.setContent(content); // Werk review-inhoud bij
return review;
}
// Verwijdert een review, controleert of de gebruiker geautoriseerd is om de review te "verwijderen"
public void deleteReview(User user, int productId, int reviewId) {
Product product = getProductById(productId); // Haal het product op aan de hand van zijn ID
boolean isDeleted = product.getReviews().removeIf(review -> {
if (review.getId().equals(reviewId)) {
authorize(user, "delete", review); // Controleer of de gebruiker de review kan verwijderen
return true;
} else {
return false;
}
});
if (!isDeleted) {
throw new ResourceNotFoundException("Review with id " + reviewId + " not found");
}
try {
permit.api.resourceInstances.delete("review:" + reviewId); // Verwijder review-broninstantie uit Permit
} catch (IOException | PermitApiError | PermitContextError e) {
throw new RuntimeException(e);
}
}
}
In het code onderstaand, de ProductController klasse handelt HTTP aanvragen in verband met producten en hun beoordelingen af. Hij exposeert endpoints voor het beheren van producten (zoals aanmaken
, bijwerken
, verwijderen
en ophalen
) en voor het beheren van productbeoordelingen.
package com.boostmytool.store.controllers;
import com.boostmytool.store.model.Product;
import com.boostmytool.store.model.Review;
import com.boostmytool.store.service.ProductService;
import io.permit.sdk.enforcement.User;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController // Geeft aan dat deze klasse een Spring REST-controller is
@RequestMapping("/api/products") // Basis-URL voor alle eindpunten in deze controller
public class ProductController {
private final ProductService productService; // ProductService-instantie om productgerelateerde bewerkingen af te handelen
@Autowired // Autowires ProductService-bean automatisch
public ProductController(ProductService productService) {
this.productService = productService;
}
// GET-verzoek om alle producten op te halen
@GetMapping
public List<Product> getAllProducts(HttpServletRequest request) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
return productService.getAllProducts(currentUser); // Roep ProductService aan om alle producten voor de gebruiker op te halen
}
// GET-verzoek om een product op te halen aan de hand van de ID
@GetMapping("/{id}")
public Product getProductById(HttpServletRequest request, @PathVariable("id") int id) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
return productService.getProduct(currentUser, id); // Roep ProductService aan om het product op ID voor de gebruiker op te halen
}
// POST-verzoek om een nieuw product toe te voegen
@PostMapping
@ResponseStatus(HttpStatus.CREATED) // Stelt de antwoordstatus in op 201 (Gemaakt)
public Product addProduct(HttpServletRequest request, @RequestBody String content) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
return productService.addProduct(currentUser, content); // Roep ProductService aan om een nieuw product toe te voegen
}
// PUT-verzoek om een bestaand product bij te werken aan de hand van de ID
@PutMapping("/{id}")
public Product updateProduct(HttpServletRequest request, @PathVariable("id") int id, @RequestBody String content) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
return productService.updateProduct(currentUser, id, content); // Roep ProductService aan om het product bij ID bij te werken
}
// DELETE-verzoek om een product te verwijderen aan de hand van de ID
@DeleteMapping("/{id}")
public String deleteProduct(HttpServletRequest request, @PathVariable("id") int id) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
productService.deleteProduct(currentUser, id); // Roep ProductService aan om het product bij ID te verwijderen
return "Deleted product with id " + id; // Geeft een succesbericht terug na verwijdering
}
// POST-verzoek om een nieuwe beoordeling aan een product toe te voegen aan de hand van de product-ID
@PostMapping("/{id}/review")
public Review addReview(HttpServletRequest request, @PathVariable("id") int id, @RequestBody String content) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
return productService.addReview(currentUser, id, content); // Roep ProductService aan om een beoordeling aan het product toe te voegen
}
// PUT-verzoek om een bestaande beoordeling bij te werken aan de hand van de product- en beoordelings-ID
@PutMapping("/{id}/review/{reviewId}")
public Review updateReview(HttpServletRequest request, @PathVariable("id") int id, @PathVariable("reviewId") int reviewId, @RequestBody String content) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
return productService.updateReview(currentUser, id, reviewId, content); // Roep ProductService aan om de beoordeling bij te werken
}
// DELETE-verzoek om een beoordeling te verwijderen aan de hand van de product- en beoordelings-ID
@DeleteMapping("/{id}/review/{reviewId}")
public String deleteReview(HttpServletRequest request, @PathVariable("id") int id, @PathVariable("reviewId") int reviewId) {
User currentUser = (User) request.getAttribute("user"); // Haalt de geverifieerde gebruiker uit het verzoek
productService.deleteReview(currentUser, id, reviewId); // Roep ProductService aan om de beoordeling te verwijderen
return "Deleted review with id " + reviewId + " from product " + id; // Geeft een succesbericht terug na verwijdering
}
}
Stap 2: Verkrijg uw Omgeving API Sleutel
In de UI Dashboard kopieer de Omgeving API Sleutel
van het actieve milieu.
Voeg vervolgens de omgeving API Sleutel
en PDP URL
toe aan het bestand application.yaml
.
permit:
pdpUrl: 'http://localhost:7766'
apiKey: "Your Permit environment API Key"
Stap 3: Implementeer Policy Decision Point (PDP)
De Policy Decision Point (PDP) wordt geïmplementeerd in uw VPC en is verantwoordelijk voor het evalueren van uw autorisatieverzoeken. De PDP zal uiterst laag latency, uitstekende prestaties, hoge beschikbaarheid en verbeterde beveiliging waarborgen.
Gebruik het commando hieronder om de Permit.io PDP container vanuit Docker
Hub te halen.
docker pull permitio/pdp-v2:latest
En start vervolgens de container.
docker run -it -p 7766:7000 --env PDP_DEBUG=True --env PDP_API_KEY=<YOUR_API_KEY> permitio/pdp-v2:latest
Stap 4: De App Uitvoeren
U kunt de applicatie uitvoeren met behulp van het volgende Gradle
-commando:
./gradlew bootRun
Producten Bekijken en Aanmaken
Laten we nu interactie hebben met de applicatie-eindpunten door middel van REQBIN.
Eerst maak een nieuwe gebruiker aan met de /api/users/signup
eindpunt.
curl -X POST "http://localhost:8080/api/users/signup" -H "Content-Type: application/json" -d 'johndoe'
U moet in staat zijn de gebruiker te zien in uw Permit-project, onder Directory > Alle Tenants.
Initieel heeft de gebruiker geen rollen, dus hij kan niet veel. Bijvoorbeeld, als u probeert de producten te lijsten, zal dit resulteren in een 403 Verboden reactie, zoals hieronder te zien is. Het 403 foutcode betekent dat de gebruiker geen toestemming heeft om toegang te krijgen tot de gevraagde resource, in dit geval de producten. U kunt meer over de verschillen tussen 401 en 403 foutcodes hier leren.
Om de gebruiker een lijst met producten te laten zien, moet u hem een kijkerrol toewijzen met de命令 hieronder:
curl -X POST "http://localhost:8080/api/users/assign-role" \
-H "Authorization: Bearer johndoe" \
-H "Content-Type: application/json" \
-d 'viewer'
U zou moeten zien dat de gebruiker johndoe
de rol kijker toegekend kreeg, zoals hieronder te zien is:
Aangezien een kijker een product kan aanmaken, kun je de commando hieronder gebruiken om een product aan te maken met de gebruiker johndoe
.
curl -X POST "http://localhost:8080/api/products" -H "Authorization: Bearer johndoe" -H "Content-Type: application/json" -d 'MacBook'
U zou moeten zien dat een nieuw product is aangemaakt met ID 1 en dat de gebruiker johndoe
als leverancier is toegevoegd.
Producten Beoordelingen Toevoegen
Om beoordelingen toe te voegen aan producten, maak een andere gebruiker aan genaamd jane
.
curl -X POST "http://localhost:8080/api/users/signup" -H "Content-Type: application/json" -d 'jane'
Om de gebruiker een beoordeling aan producten toe te voegen, wijs hen de rol kijker
toe met de commando hieronder:
curl -X POST "http://localhost:8080/api/users/assign-role" \
-H "Authorization: Bearer jane" \
-H "Content-Type: application/json" \
-d 'viewer'
Dan kun je een beoordeling toevoegen aan het product toegevoegd door johndoe
met de commando hieronder:
curl -X POST "http://localhost:8080/api/products/1/review" -H "Authorization: Bearer jane" -H "Content-Type: application/json" -d 'The product was in good quality'
Gefeliciteerd! U heeft de project voor deze handleiding voltooid.
Volgende Stappen
Nu u heeft geleerd hoe u Permit.io gebruikt om gekleurde toegangsautorisatie in uw Java- en Spring Boot-toepassingen uit te voeren, zou u misschien verder willen exploren.
Hier zijn enkele waardevolle bronnen:
Voor we afsluiten
Ik hoop dat u deze handleiding nuttig vond.
Hier zijn enkele van mijn andere recente blogposts die u misschien leuk vindt:
Bekijk mijn blog DTA voor meer handleidingen over uitstekende ontwikkelertools.
Volg me op Twitter voor live updates over mijn andere projecten.
Fijn coderen.
Source:
https://www.freecodecamp.org/news/fine-grained-authorization-in-java-and-springboot/