Deesdae het ons meer en meer kommer oor prestasie, en terselfdertyd wil ons weet hoe stelsels vinnig en betroubaar kan kommunikeer. Ons wil baie keer inligting stuur en dit sover moontlik vertroulik en veilig hou. Sensitiewe data moet soms ook publiek deur die web beweeg en aksies aan die ander kant van die draad veroorsaak. Meestal wil ons aksies genereer wat datamutasies sal veroorsaak. In hierdie gevalle kyk ons nie net na die beskerming van ons data nie. Ons wil seker maak dat die aksies wat veroorsaak word deur die stuur van ons data, vertrou word. Ons kan ons data op verskeie maniere beskerm. Meestal stuur ons die data via 'n (Transport Layer Security) veilige verbinding. Dit sal verseker dat ons data deur die draad geïnkripteer word. Ons gebruik sertifikate om vertrouensverhoudings tussen twee partye te skep en dit te bereik. In hierdie artikel wil ek die standaard bespreek en verder sien hoe ons in 'n algemene toepassing kan integreer. In hierdie geval sal ons na kyk. Kom ons kyk na 'n paar basiese konsepte. of JSON Web Token, of nog beter, JavaScript Object Notation Web Token, is 'n standaard wat in gedefinieer word. Hierdie standaard is, soos alle (Request For Comments) standaarde, gedefinieer, geskryf en gepubliseer deur die (Internet Engineering Task Force). Dit kan op verskeie maniere gedefinieer word. Oor die algemeen kan ons sê dat 'n kompakte, veilige vorm is om eise tussen twee partye oor te dra. Een manier om te vereenvoudig wat 'n eis is, is basies om dit te beskryf as 'n naam/waarde-paar wat inligting bevat. Ons het hierdie inligting nodig om 'n paar belangrike aspekte van ons internetkommunikasie te waarborg. Ons moet seker maak dat die inligting wat ons ontvang in die eerste instansie bekragtig en vertrou word. Dan moet ons dit bekragtig. Dit is basies dit.Om hierdie standaard te implementeer, kan ons verskeie raamwerke gebruik wat ons kan help om 'n Java-ondernemingstoepassing te implementeer. Spring Boot word wyd gebruik. Baie keer word dit ook onder 'n ander naam toegedraai in behoorlike sagteware van sekere organisasies soos banke en ander finansiële organisasies. Vir ons voorbeeld het ek besluit om iets anders te doen. In plaas van Spring Boot, gaan ons na 'n voorbeeld met kyk. Die punt is om presies te identifiseer wat is en hoe dit lyk. Java Enterprise Applications is basies toepassings wat in 'n toepassingsbediener ontplooi kan word of net op hul eie kan hardloop deur die gebruik van 'n ingebedde bediener. As 'n voorbeeld, Spring Boot-toepassings loop op 'n ingebedde Tomcat-bediener. In hierdie artikel sal ons fokus op gestel word. Net soos Spring Boot bevat dit ook 'n ingebedde bediener. Behalwe dat dit in hierdie geval Jetty genoem word. Dit word in kombinasie met Weld gebruik om CDI (Context Dependency Injection) te verskaf. Alle Java en tegnologie standaarde is versoenbaar met hierdie . TLS JWT JWT Enterprise KumuluzEE JWT RFC7519 RFC IETF JWT KumuluzEE JWT KumuluzEE EE Jakarta EE framework 2. Geval Voorbeeld Om 'n voorbeeld te gee van hoe in sy basiese vorm werk, moes ek aan 'n manier dink om dit aan te bied. Klassieke voorbeelde waar sekuriteit 'n bekommernis is, is banke. Om egter 'n hele bankaansoek te maak om te wys hoe werk, sal 'n mors van tyd wees en miskien sal te veel konsepte betrokke wees. In plaas daarvan, wat ek gemaak het, is 'n baie eenvoudige bankstelsel. Ons grootste bekommernis is om te wys hoe data deur die draad vloei en hoe gebruikers toegang tot sekere areas van ons toepassing kry. Ek gaan ook nie TLS bespreek of hoe ons geïnkripteer inligting deur die draad kan stuur nie. Ons sal ons fokus op in sy suiwerste vorm behou. Ons saak is 'n bankstelsel wat gebruik word deur 'n groep wat die natuur en die omgewing verdedig. Dit is net 'n prettige manier om te wys hoe werk. Die hoofkarakter van hierdie Liga van die Natuur is Lucy, wat 'n algemene karakter in al my artikels word. JWT JWT JWT JWT 3. Argitektuur Voordat ons begin, kom ons skets net ons lopende toepassing. Dit is 'n baie eenvoudige toepassing, maar dit is steeds 'n goeie ding om dit te teken: Die rede waarom dit so eenvoudig is, is dat aangesien op elke versoek nagegaan word en elke versoek teen die publieke sleutel geverifieer word, ons weet dat solank ons die korrekte teken op elke versoek stuur, ons sal kan deurkom. kan geïntegreer word met OAuth2, Okta SSO of enige ander magtigingsmeganisme. In hierdie geval is wat ons doen om verifikasie en magtiging te vestig. In ons toepassing gaan ons gebruik en daarmee ons boodskap verifieer met 'n handtekening. Ons sal egter nie by die toepassing aanmeld nie. In plaas daarvan sal ons gebruikers magtig om ons toepassing te gebruik na suksesvolle verifikasie. Op hierdie stadium is dit maklik om te sien dat in sy kern eintlik 'n baie klein deel van 'n volledige toepassing is. Nietemin moet sekere funksies bygevoeg word. Dit is die hulpbronne wat ons benodig: JWT JWT JWT JWT Balansisteem Kredietstelsel Kom ons sê net dat ons basiese stelsel net geld- en kredietversoeke sal registreer. In wese sal dit net waardes ophoop. Kom ons neem ook aan dat sommige mense krediet sal kan kry en ander nie. Sommige mense sal geld kan stoor en ander mense sal krediet kan kry. 4. Die keuse van tegnologieë Soos in die inleiding genoem, sal ons as ons ondernemingstoepassingsraamwerk gebruik, en ons sal 'n ultra-basiese toepassing implementeer op 'n manier dat ons na basiese terminologie en -konsepte kan kyk. Maak seker dat u die korrekte Java-weergawe het. Op hierdie stadium sal ons 'n minimum Java 17 SDK moet installeer. Ons benodig maven, git, 'n Java-versoenbare IDE soos IntelliJ, en 'n soort dop. KumuluzEE JWT 5. Opstelling Om ons toepassing te begin, het ons 'n paar afhanklikhede. Dit is hoofsaaklik omdat , net soos Spring Boot, 'n paar afhanklikhede benodig. Kom ons kyk kortliks na die POM-lêer: KumuluzEE KumuluzEE <dependencies> <dependency> <groupId>com.kumuluz.ee.openapi</groupId> <artifactId>kumuluzee-openapi-mp</artifactId> </dependency> <dependency> <groupId>com.kumuluz.ee.openapi</groupId> <artifactId>kumuluzee-openapi-mp-ui</artifactId> </dependency> <dependency> <groupId>com.kumuluz.ee</groupId> <artifactId>kumuluzee-microProfile-3.3</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.mockk</groupId> <artifactId>mockk-jvm</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.ninja-squad</groupId> <artifactId>springmockk</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.kotest</groupId> <artifactId>kotest-assertions-core-jvm</artifactId> <scope>test</scope> </dependency> </dependencies> Kom ons bespreek 'n paar afhanklikhede kortliks. Soos jy dit lees, volg asseblief ons -lêer van bo na onder. Dit is belangrik om die volgende verduideliking te verstaan. Ons benodig 'n pakket van afhanklikhede om ons toepassing te laat werk. , Gelukkig bied aan ons mikroprofielbiblioteke wat basiese standaardbundels bevat om hierdie toepassing te begin. Dit is alles vervat in die -Mikroprofiel-biblioteek. Om ons toepassing te kan opstel met al die -parameters wat ons benodig, moet ons 'n MicroProfile-biblioteek daarby voeg. Terselfdertyd benodig ons 'n JSON-verwerkingsbiblioteek. Dit sal wees wat Johnson Core doen. Ons het natuurlik die kern van nodig om te werk. Jetty is die onderliggende bediener wat die raamwerk bestuur. Dit is hoekom ons dit nodig het in ons afhanklikhede. Aangesien ons benodig, benodig ons ook 'n biblioteek wat dit ondersteun. Om ons REST-eindpunte te aktiveer, het ons die resbiblioteek van nodig. Om ons API te kry, benodig ons dan 'n Geronimo-biblioteek. Dit sal verseker dat ons 'n implementering van beskikbaar het. Ons moet ook ons en sy inhoud interpreteer. Lombok is nie regtig per se nodig nie. Dit maak alles net mooi en blink! Logback is ook belangrik om te hê sodat ons logboeke beter kan interpreteer en ons resultate kan verstaan. Kom ons kyk nou na ons lêergids. Om te begin, kom ons verstaan eers wat ons verwag om in hierdie gids te vind. Ons moet ons toepassing opstel met iets wat verband hou met , Logback en laastens moet ons iets sê oor die bone wat ons gaan skep. Kom ons kyk na die eenvoudigste lêer daar. Die boontjies.xml kan gevind word in META-INF: pom.xml KumuluzEE KumuluzEE JWT KumuluzEE KumuluzEE CDI KumuluzEE JSR-374 JWT JSON-formatted resources JWT <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" xmlns:weld="http://jboss.org/schema/weld/beans" bean-discovery-mode="all"> <weld:scan> <weld:exclude name="org.jesperancinha.fintech.model.Accounts"/> </weld:scan> </beans> Dit is net 'n tipiese en soos jy dalk nou dink, 'n bietjie van 'n ou lêer. Op hierdie stadium is die idee net om aan die gang te kry. Ons het wel 'n uitsluit-aksie. Dit sê vir Weld om nie klasrekeninge in sy skandering vir boontjies-aksie in ag te neem nie. Dit is belangrik, want met die implementering wat ons gebruik, sal basies elke klas met 'n leë konstruktor as 'n boontjie beskou. Ons sal later sien hoekom ons nie wil hê dat rekeninge as 'n boontjie beskou moet word nie. Laat ons vir die oomblik in gedagte hou dat ons versoeke onder die Versoek-omvang rig. Dit is logies omdat elke versoek 'n ander gebruiker kan hê. Kom ons kyk nou hoe " " geïmplementeer word. Dit word ook gevind in : KumuluzEE Weld logback META-INF <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="INFO"> <appender-ref ref="STDOUT"/> </root> </configuration> Dit is net 'n baie eenvoudige konfigurasie vir ons . Ten slotte, miskien die belangrikste lêer van ons toepassing. Dit is die config-sjabloon. Op hierdie stadium is dit belangrik om daarop te let dat sommige van die lêers wat ek in hierdie projek geskep het, deel is van 'n sjabloonstruktuur. Ek sal later meer daaroor verduidelik. Hierdie sjabloonlêer is veronderstel om in 'n config.yml-lêer verander te word wat deur MicroProfile gelees sal word. Hierdie lêer is by die wortel van hulpbronne geleë: logs kumuluzee: name: your-financeje-banking version: 1.0.0 jwt-auth: public-key: {{ publicKey }} issuer: {{ issuer }} healthy: true Ons sal later sien wat presies al hierdie eiendomme eintlik beteken. Almal van hulle is selfverduidelikend. Die publicKey en uitreiker is almal parameters wat vervang sal word. Ons sal dit later ondersoek. Ons bash-skrifte sal seker maak dat hulle vervang word. Ons is amper gereed om te gaan kodeer, maar kom ons kyk eers na ons tokenstruktuur. JWT 6. Hands-on kode Kom ons maak ons baie klein aansoek. Hierdie afdeling sal verduidelik hoe ons ons aansoek kan kry om met te werk. Wat ons wil sien, is of ons gebruikers kan spesifiseer om toegang te verkry tot sommige van ons metodes en nie ander nie. Een van die maniere om na hierdie kode te begin kyk, is om eers na ons gewone token te kyk. Hier is ons admin voorbeeld: JWT REST JWT { "iss": "joaofilipesabinoesperancinha", "jti": "01MASTERFINANCE", "sub": "admin", "aud": "nature", "upn": "admin", "groups": [ "user", "admin", "client", "credit" ], "user_id": 1, "access": "TOP", "name": "Admin" } Daar word na elkeen van hierdie name in ons verwys as eise. In ons voorbeeld sien ons 'n paar Voorbehou-aansprake: JSON " " - Dit is die uitreiker van die teken. Ons kan arbitrêr 'n waarde hiervoor kies. Die waarde van hierdie parameter moet ooreenstem met die uitreiker veranderlike wat vervang moet word in die config.yml wat ons voorheen gesien het. iss " " - Dit is 'n unieke identifiseerder van die teken. Ons kan byvoorbeeld hierdie eis gebruik om te verhoed dat 'n teken twee of meer keer gebruik word. jti " " - Dit is die onderwerp van die teken. Dit kan die gebruiker wees of enigiets waarvan ons hou. Dit is belangrik om in gedagte te hou dat dit ook gebruik kan word as 'n identifiseerder, sleutel, benaming of enigiets wat ons wil hê. sub " " — Gebruikershoofnaam. Dit word gebruik om die skoolhoof te identifiseer wat die gebruiker gebruik. upn " " — Dit is 'n reeks van die groepe waaraan die huidige gebruiker behoort. Dit sal in wese bepaal wat 'n versoek met hierdie teken kan doen. In ons teken sien ons dan 'n paar persoonlike eise. Ons kan dit net so goed gebruik as die Reserve-eise groups " " — Ons sal dit gebruik om die gebruiker-ID te stel. user_id " " — Ons sal die toegangsvlak van die gebruiker bepaal. access " " — Die naam van die gebruiker. name 7. Hands-on kode Kom ons maak 'n opsomming van wat ons tot dusver weet. Ons weet ons sal met tekens kommunikeer met 'n struktuur wat ons bepaal het. Verder het ons die konfigurasie van ons toepassing, die logback-konfigurasie opgestel en laastens het ons 'n pasgemaakte konfigurasie vir die ondernemingsboonopsoek opgestel. Kom ons kyk na die pakketmodel. Hier sal ons 3 klasse vind. Hierdie klasse verteenwoordig basies net 'n samevoeging van rekeninge en die verteenwoordiging tussen en . Op hierdie manier kan ons begin deur na kotlin-lêer Model.kt te kyk waar geleë is by: client account Client data class Client constructor( @JsonProperty var name: String ?= null ) Hierdie eerste modelklas is die voorstelling van ons kliënt. Ons vir ons saak het net 'n naam. Dit is die gebruikersnaam wat deur die " " kenmerknaam verteenwoordig word. Verder het ons : client jwt Account data class Account( @JsonProperty val accountNumber: String?, @JsonProperty val client: Client? = null, @JsonProperty var currentValue: BigDecimal = BigDecimal.ZERO, @JsonProperty var creditValue: BigDecimal = BigDecimal.ZERO ) { fun addCurrentValue(value: Long) = Account( accountNumber, client, currentValue .add(BigDecimal.valueOf(value)), creditValue ) fun addCreditValue(value: Long): Account = Account( accountNumber, client, currentValue, currentValue .add(BigDecimal.valueOf(value)) ) } In hierdie klas stel ons basies 'n rekeningnommer, 'n kliënt, 'n huidige waarde en laastens 'n kredietwaarde op. Let daarop dat ons alle waardes na 0 stel. Ons gebruik ook BigDecimal, bloot omdat ons met geld te doen het. Geld moet presies wees en kan nie stelsel-afrondings of -afrondings ondervind nie. Dit beteken met ander woorde en as 'n voorbeeld dat 'n getal soos 0. euro die hele tyd daardie getal moet bly. Ons wil ook waardes by ons rekening voeg. Dit is waar die metode addCurrentValue ontstaan. Om dieselfde redes sal ons ook ons krediet aanvul met die . Ten slotte, in die laaste stuk van ons data-opstelling kom ons teë: 0000000000000000000000000000000000000000000000000001 addCreditValue Accounts open class Accounts constructor( open val accountMap: MutableMap<String, Account> = mutableMapOf() ) Dit is in wese net 'n versamelaar van al ons rekeninge. Ons sal sy kaartinhoud gebruik om die gedrag van 'n databasis na te boots. Kom ons kyk nou na die kontroleerderpakket. Dit is waar ons ons toepassing skep wat met ons datamodel loop. Kom ons kyk eers na klas : BankApplication @LoginConfig(authMethod = "MP-JWT") @ApplicationPath("/") @DeclareRoles("admin", "creditor", "client", "user") class BankApplication : Application() Hiermee sê ons 3 belangrike dinge. Met die LoginConfig-aantekening definieer ons dit om -tokens volgens MicroProfile te gebruik en te verstaan. Die ApplicationPath definieer die toepassingswortel. Dit is waar die URL van die toepassing sal begin. In ons voorbeeld sal dit wees. Laastens definieer die DeclareRoles die rolle wat deur ons aansoek gebruik en aanvaar gaan word. Rolle en Groepe is uitruilbare terme in hierdie situasie. Om inspuiting doeltreffend te laat werk, skep ons 'n aantekening spesifiek om die rekeningkaart te identifiseer: JWT HTTP://localhost:8080 annotation class AccountsProduct Gaan in volskermmodus Verlaat volskermmodus Vervolgens skep ons 'n kasvoorwerpfabriek AccountsFactory: class AccountsFactory : Serializable { @Produces @AccountsProduct @ApplicationScoped fun accounts(): Accounts = Accounts(mutableMapOf()) companion object { @Throws(JsonProcessingException::class) fun createResponse( currentAccount: Account, name: JsonString, accounts: Accounts, log: Logger, objectMapper: ObjectMapper, principal: Principal?, jsonWebToken: JsonWebToken? ): Response { val jsonObject = Json.createObjectBuilder() .add("balance", currentAccount.currentValue) .add("client", name) .build() accounts.accountMap[name.string] = currentAccount log.info("Principal: {}", objectMapper.writeValueAsString(principal)) log.info("JSonWebToken: {}", objectMapper.writeValueAsString(jsonWebToken)) return Response.ok(jsonObject) .build() } } } Hierdie fabriek is die rede waarom ons opsoek spesifiek vir gedeaktiveer het. In plaas daarvan om die opsoekproses toe te laat om 'n boontjie te skep, skep ons self die aggregator-instansie. Deur die Produseer-aantekening te gebruik, kan ons die boontjie skep. Met behulp van ons pasgemaakte aantekening, AccountsProduct, maak ons die gebruik van hierdie boontjie meer spesifiek. Ten slotte, deur te gebruik, definieer ons die omvang daarvan as die . Met ander woorde, die rekeningaggregasieboon sal optree as 'n enkelton-objek regoor die toepassing. Die " " is net 'n generiese metode om JSON-antwoorde te skep. Wat ons nou nodig het, is twee "Hulpbronne". Dit is basies dieselfde as " " in die lente. Dit is 'n ander naam, maar dit het presies dieselfde gebruik. Kom ons kyk na die -klas: Accounts ApplicationScoped Application createResponse Controllers AccountsResource @Path("accounts") @RequestScoped @Produces(MediaType.APPLICATION_JSON) open class AccountResource { @Inject @AccountsProduct open var accounts: Accounts? = null @Inject open var principal: Principal? = null @Inject open var jsonWebToken: JsonWebToken? = null @Inject @Claim("access") open var access: JsonString? = null @Claim("iat") @Inject open var iat: JsonNumber? = null @Inject @Claim("name") open var name: JsonString? = null @Inject @Claim("user_id") open var userId: JsonNumber? = null @POST @RolesAllowed("admin", "client", "credit") @Throws(JsonProcessingException::class) open fun createAccount(): Response = createResponse( requireNotNull(accounts).accountMap[requireNotNull(name).string] ?: Account( client = Client(name = requireNotNull(name).string), accountNumber = UUID.randomUUID().toString() ) ) @POST @RolesAllowed("admin", "user") @Path("user") @Throws(JsonProcessingException::class) open fun createUser(): Response { return createResponse( requireNotNull(accounts).accountMap[requireNotNull(name).string] ?: Account( client = Client(name = requireNotNull(name).string), accountNumber = UUID.randomUUID().toString() ) ) } @GET @RolesAllowed("admin", "client") @Throws(JsonProcessingException::class) open fun getAccount(): Response? { return createResponse( requireNotNull(accounts).accountMap[requireNotNull(name).string] ?: return Response.serverError() .build() ) } @PUT @RolesAllowed("admin", "client") @Consumes(MediaType.APPLICATION_JSON) @Throws( JsonProcessingException::class ) open fun cashIn(transactionBody: TransactionBody): Response? { val userAccount = requireNotNull(accounts).accountMap[requireNotNull(name).string] ?: return Response.serverError() .build() val currentAccount = userAccount.addCurrentValue(transactionBody.saldo?: 0) requireNotNull(accounts).accountMap[requireNotNull(name).string] = currentAccount return createResponse(currentAccount) } @GET @Path("all") @Produces(MediaType.APPLICATION_JSON) @Throws( JsonProcessingException::class ) open fun getAll(): Response? { val allAccounts = ArrayList( requireNotNull(accounts).accountMap .values ) logger.info("Principal: {}", objectMapper.writeValueAsString(principal)) logger.info("JSonWebToken: {}", objectMapper.writeValueAsString(jsonWebToken)) return Response.ok(allAccounts) .build() } @GET @Path("summary") @Throws(JsonProcessingException::class) open fun getSummary(): Response? { val totalCredit = requireNotNull(accounts).accountMap .values .map(Account::currentValue) .stream() .reduce { result, u -> result.add(u) } .orElse(BigDecimal.ZERO) val jsonObject = Json.createObjectBuilder() .add("totalCurrent", totalCredit) .add("client", "Mother Nature Dream Team") .build() logger.info("Summary") logger.info("Principal: {}", objectMapper.writeValueAsString(principal)) logger.info("JSonWebToken: {}", objectMapper.writeValueAsString(jsonWebToken)) return Response.ok(jsonObject) .build() } @GET @RolesAllowed("admin", "client") @Path("jwt") open fun getJWT(): Response? { val jsonObject = Json.createObjectBuilder() .add("jwt", requireNotNull(jsonWebToken).rawToken) .add("userId", requireNotNull(userId).doubleValue()) .add("access", requireNotNull(access).string) .add("iat", requireNotNull(iat).doubleValue()) .build() return Response.ok(jsonObject) .build() } @Throws(JsonProcessingException::class) private fun createResponse(currentAccount: Account): Response = AccountsFactory.createResponse( currentAccount, requireNotNull(name), requireNotNull(accounts), logger, objectMapper, principal, jsonWebToken ) companion object { val objectMapper: ObjectMapper = ObjectMapper() val logger: Logger = LoggerFactory.getLogger(AccountResource::class.java) } } Neem 'n oomblik om meer in detail na hierdie klas te kyk. Die -aantekening definieer hoe om hierdie hulpbron vanaf die wortel te bereik. Onthou dat ons "/" as die wortel gebruik. In hierdie geval is "rekeninge" ons worteltoegangspunt vir hierdie hulpbron. Al ons bronne, in ons geval is net twee wat met omvang RequestResource loop. Met annotasie bepaal Produces dat alle antwoorde op alle versoeke, ongeag hul tipe, die vorm van JSON-geformateerde boodskappe sal aanneem. Om ons in te spuit, gebruik ons net die kombinasie van die Inject annotation en annotasie: Path aggregator AccountsProduct @Inject @AccountsProduct open var accounts: Accounts? = null Dit pas by wat ons in die fabriek gedefinieer het. Verder spuit ons ook twee belangrike elemente van sekuriteit in. 'n en die : principal jsonWebToken @Inject open var principal: Principal? = null @Inject open var jsonWebToken: JsonWebToken? = null Beide en sal dieselfde wees, en ons sal dit in ons logboeke sien. In ons hulpbronne kan ons altyd eise van 'n versoek met 'n sekere teken inspuit: JsonWebToken Principal @Inject @Claim("name") open var name: JsonString? = null @Inject @Claim("user_id") open var userId: JsonNumber? = null Dit word bereik met die kombinasie van die en -aantekeninge. Die naam wat onder die -aantekening geplaas word, definieer watter eis ons wil invoeg. Ons moet versigtig wees met die tipe waarmee ons ons parameters definieer. In ons voorbeeld het ons net en -tipes nodig. Kom ons kyk eers hoe ons rekeninge en gebruikers skep: Inject Claim Claim JsonString JsonNumber @POST @RolesAllowed("admin", "client", "credit") @Throws(JsonProcessingException::class) open fun createAccount(): Response = createResponse( requireNotNull(accounts).accountMap[requireNotNull(name).string] ?: Account( client = Client(name = requireNotNull(name).string), accountNumber = UUID.randomUUID().toString() ) ) @POST @RolesAllowed("admin", "user") @Path("user") @Throws(JsonProcessingException::class) open fun createUser(): Response { return createResponse( requireNotNull(accounts).accountMap[requireNotNull(name).string] ?: Account( client = Client(name = requireNotNull(name).string), accountNumber = UUID.randomUUID().toString() ) ) } Die skep van rekeninge en gebruikers Die doel hier is om metodes te kan skei en hulle verskillende toestemmings te gee. In ons voorbeeld skep hulle albei net 'n rekening, maar dit is belangrik om op te let dat slegs gebruikers met rollegebruikers die createUser-metode kan gebruik. Op dieselfde manier kan slegs gebruikers met rolle van kliënt en krediet toegang kry tot die metode createAccount. Kom ons kyk nou in detail na die PUT-versoekmetode van hierdie hulpbron: @PUT @RolesAllowed("admin", "client") @Consumes(MediaType.APPLICATION_JSON) @Throws( JsonProcessingException::class ) open fun cashIn(transactionBody: TransactionBody): Response? { val userAccount = requireNotNull(accounts).accountMap[requireNotNull(name).string] ?: return Response.serverError() .build() val currentAccount = userAccount.addCurrentValue(transactionBody.saldo?: 0) requireNotNull(accounts).accountMap[requireNotNull(name).string] = currentAccount return createResponse(currentAccount) } Inbetaal Ons weet dat aantekening aandui dat hierdie metode slegs toeganklik is met versoeke van tipe . Annotation Path sê dan vir Jetty dat die pad na hierdie metode 'n waarde is. Dit staan ook bekend as 'n . Laastens kan ons hierdie metode definieer wat slegs toegelaat word om gebruik te word deur gebruikers met rolle admin of kliënt. Die invoerwaarde word dan deur die gebruik van die PathParam na ons Langwaarde-veranderlike oorgedra. As ons geen rolle definieer nie, sal enige gebruiker met die regte token toegang tot hierdie metodes kan verkry. word in dieselfde geïmplementeer manier: PUT PUT PathParam CreditResource @Path("credit") @RequestScoped @Produces(MediaType.APPLICATION_JSON) open class CreditResource { @Inject @AccountsProduct open var accounts: Accounts? = null @Inject open var principal: Principal? = null @Inject open var jsonWebToken: JsonWebToken? = null @Inject @Claim("access") open var access: JsonString? = null @Inject @Claim("iat") open var iat: JsonNumber? = null @Inject @Claim("name") open var name: JsonString? = null @Inject @Claim("user_id") open var userId: JsonNumber? = null @GET @RolesAllowed("admin", "credit") @Throws(JsonProcessingException::class) open fun getAccount(): Response = requireNotNull(accounts).let { accounts -> createResponse( accounts.accountMap[requireNotNull(name).string] ?: return Response.serverError().build() ) } @PUT @RolesAllowed("admin", "credit") @Consumes(MediaType.APPLICATION_JSON) @Throws( JsonProcessingException::class ) open fun cashIn(transactionBody: TransactionBody) = requireNotNull(accounts).let { accounts -> requireNotNull(name).let { name -> accounts.accountMap[name.string] = (accounts.accountMap[name.string] ?: return Response.serverError() .build()).addCreditValue(transactionBody.saldo?: 0L) createResponse( (accounts.accountMap[name.string] ?: return Response.serverError() .build()).addCreditValue(transactionBody.saldo?: 0L) ) } } @GET @Path("all") @Produces(MediaType.APPLICATION_JSON) @Throws( JsonProcessingException::class ) open fun getAll(): Response? { val allAccounts = ArrayList( requireNotNull(accounts).accountMap .values ) logger.info("Principal: {}", objectMapper.writeValueAsString(principal)) logger.info("JSonWebToken: {}", objectMapper.writeValueAsString(jsonWebToken)) return Response.ok(allAccounts) .build() } @GET @Path("summary") @Produces(MediaType.APPLICATION_JSON) @Throws( JsonProcessingException::class ) open fun getSummary(): Response? { val totalCredit = requireNotNull(accounts).accountMap .values .map(Account::creditValue) .stream() .reduce { total, v -> total.add(v) } .orElse(BigDecimal.ZERO) val jsonObject = Json.createObjectBuilder() .add("totalCredit", totalCredit) .add("client", "Mother Nature Dream Team") .build() logger.info("Summary") logger.info("Principal: {}", objectMapper.writeValueAsString(principal)) logger.info("JSonWebToken: {}", objectMapper.writeValueAsString(jsonWebToken)) return Response.ok(jsonObject) .build() } @GET @RolesAllowed("admin", "client") @Path("jwt") open fun getJWT(): Response? { val jsonObject = Json.createObjectBuilder() .add("jwt", requireNotNull(jsonWebToken).rawToken) .add("userId", requireNotNull(userId).doubleValue()) .add("access", requireNotNull(access).string) .add("iat", requireNotNull(iat).doubleValue()) .build() return Response.ok(jsonObject) .build() } @Throws(JsonProcessingException::class) private fun createResponse(currentAccount: Account): Response { return AccountsFactory.createResponse( currentAccount, requireNotNull(name), requireNotNull(accounts), logger, objectMapper, principal, jsonWebToken ) } companion object { val objectMapper: ObjectMapper = ObjectMapper() val logger: Logger = LoggerFactory.getLogger(CreditResource::class.java) } } Die enigste verskil is dat in plaas daarvan om rolle en te gebruik, gebruik ons nou en rolle. Let ook op dat rekeninge vir gebruikers nooit in hierdie geskep sal word nie. Dit is slegs moontlik via die rekening se . Noudat ons weet hoe die kode geïmplementeer word, laat ons eers opsom watter metodes ons in ons diens beskikbaar gestel het. admin client admin credit resource resource REST 8. Toepassingsgebruik Kom ons kyk na die lys van die dienste wat gebruik word: Tik, URL, Loonvrag, Resultaat, Rolle toegelaat PLAAS, krediete, Alle http://localhost:8080/accounts,n/a,geskep rekening, admin/kliënt/krediet PLAAS, http://localhost:8080/accounts/user,n/a,geskep gebruiker, admin/gebruiker KRY, http://localhost:8080/accounts,n/a,Matching rekening, admin/kliënt PUT, http://localhost:8080/accounts,{saldo: Long}, Huidige balans, admin/kliënt KRY, http://localhost:8080/accounts/all,n/a,All lopende rekeninge, Alle KRY, http://localhost:8080/accounts/summary,n/a,Som van alle saldo's, Alle KRY, http://localhost:8080/credit,n/a,Matching rekening, admin/kliënt PUT, http://localhost:8080/credit,{saldo: Long}, huidige krediet, admin/kliënt KRY, http://localhost:8080/credit/all,n/a,All krediete, Alle KRY, http://localhost:8080/credit/summary,n/a,Som 9. Genereer toetsomgewing Ek het 'n -lêer in die wortelgids geskep. Hierdie lêer word "setupCertificates.sh" genoem. Kom ons kyk daarna om 'n idee te kry van wat dit doen: bash #!/bin/bash mkdir -p your-finance-files cd your-finance-files || exit openssl genrsa -out baseKey.pem openssl pkcs8 -topk8 -inform PEM -in baseKey.pem -out privateKey.pem -nocrypt openssl rsa -in baseKey.pem -pubout -outform PEM -out publicKey.pem echo -e '\033[1;32mFirst test\033[0m' java -jar ../your-finance-jwt-generator/target/your-finance-jwt-generator.jar \ -p ../jwt-plain-tokens/jwt-token-admin.json \ -key ../your-finance-files/privateKey.pem >> token.jwt CERT_PUBLIC_KEY=$(cat ../your-finance-files/publicKey.pem) CERT_ISSUER="joaofilipesabinoesperancinha" echo -e "\e[96mGenerated public key: \e[0m $CERT_PUBLIC_KEY" echo -e "\e[96mIssued by: \e[0m $CERT_ISSUER" echo -e "\e[96mYour token is: \e[0m $(cat token.jwt)" cp ../your-financeje-banking/src/main/resources/config-template ../your-financeje-banking/src/main/resources/config_copy.yml CERT_CLEAN0=${CERT_PUBLIC_KEY//"/"/"\/"} CERT_CLEAN1=${CERT_CLEAN0//$'\r\n'/} CERT_CLEAN2=${CERT_CLEAN1//$'\n'/} CERT_CLEAN3=$(echo "$CERT_CLEAN2" | awk '{gsub("-----BEGIN PUBLIC KEY-----",""); print}') CERT_CLEAN4=$(echo "$CERT_CLEAN3" | awk '{gsub("-----END PUBLIC KEY-----",""); print}') CERT_CLEAN=${CERT_CLEAN4//$' '/} echo -e "\e[96mCertificate cleanup: \e[0m ${CERT_CLEAN/$'\n'/}" sed "s/{{ publicKey }}/$CERT_CLEAN/g" ../your-financeje-banking/src/main/resources/config_copy.yml > ../your-financeje-banking/src/main/resources/config_cert.yml sed "s/{{ issuer }}/$CERT_ISSUER/g" ../your-financeje-banking/src/main/resources/config_cert.yml > ../your-financeje-banking/src/main/resources/config.yml rm ../your-financeje-banking/src/main/resources/config_cert.yml rm ../your-financeje-banking/src/main/resources/config_copy.yml echo -e "\e[93mSecurity elements completely generated!\e[0m" echo -e "\e[93mGenerating tokens...\e[0m" TOKEN_FOLDER=jwt-tokens mkdir -p ${TOKEN_FOLDER} # CREATE_ACCOUNT_FILE=createAccount.sh CREATE_USER_FILE=createUser.sh SEND_MONEY_FILE=sendMoney.sh ASK_CREDIT_FILE=askCredit.sh TOKEN_NAME_VALUE=tokenNameValue.csv echo "#!/usr/bin/env bash" > ${CREATE_ACCOUNT_FILE} chmod +x ${CREATE_ACCOUNT_FILE} echo "#!/usr/bin/env bash" > ${CREATE_USER_FILE} chmod +x ${CREATE_USER_FILE} echo "#!/usr/bin/env bash" > ${SEND_MONEY_FILE} chmod +x ${SEND_MONEY_FILE} echo "#!/usr/bin/env bash" > ${ASK_CREDIT_FILE} chmod +x ${ASK_CREDIT_FILE} for item in ../jwt-plain-tokens/jwt-token*.json; do if [[ -f "$item" ]]; then filename=${item##*/} per_token=${filename/jwt-token-/} token_name=${per_token/.json/} cp "${item}" jwt-token.json java -jar ../your-finance-jwt-generator/target/your-finance-jwt-generator.jar \ -p jwt-token.json \ -key ../your-finance-files/privateKey.pem > token.jwt cp token.jwt ${TOKEN_FOLDER}/token-"${token_name}".jwt token=$(cat token.jwt) echo "# Create account: ""${token_name}" >> ${CREATE_ACCOUNT_FILE} echo "echo -e \"\e[93mCreating account \e[96m${token_name}\e[0m\"" >> ${CREATE_ACCOUNT_FILE} echo curl -i -H"'Authorization: Bearer ""${token}""'" http://localhost:8080/accounts -X POST >> ${CREATE_ACCOUNT_FILE} echo "echo -e \"\e[93m\n---\e[0m\"" >> ${CREATE_ACCOUNT_FILE} echo "# Create user: ""${token_name}" >> ${CREATE_USER_FILE} echo "echo -e \"\e[93mCreating user \e[96m${token_name}\e[0m\"" >> ${CREATE_USER_FILE} echo curl -i -H"'Authorization: Bearer ""${token}""'" http://localhost:8080/accounts/user -X POST >> ${CREATE_USER_FILE} echo "echo -e \"\e[93m\n---\e[0m\"" >> ${CREATE_USER_FILE} echo "# Send money to: "${token_name} >> ${SEND_MONEY_FILE} echo "echo -e \"\e[93mSending money to \e[96m${token_name}\e[0m\"" >> ${SEND_MONEY_FILE} echo curl -i -H"'Content-Type: application/json'" -H"'Authorization: Bearer ""${token}""'" http://localhost:8080/accounts -X PUT -d "'{ \"saldo\": "$((1 + RANDOM % 500))"}'" >> ${SEND_MONEY_FILE} echo "echo -e \"\e[93m\n---\e[0m\"" >> ${SEND_MONEY_FILE} echo "# Asking money credit to: "${token_name} >> ${ASK_CREDIT_FILE} echo "echo -e \"\e[93mAsking credit from \e[96m${token_name}\e[0m\"" >> ${ASK_CREDIT_FILE} echo curl -i -H"'Content-Type: application/json'" -H"'Authorization: Bearer ""${token}""'" http://localhost:8080/credit -X PUT -d "'{ \"saldo\": "$((1 + RANDOM % 500))"}'">> ${ASK_CREDIT_FILE} echo "echo -e \"\e[93m\n---\e[0m\"" >> ${ASK_CREDIT_FILE} echo "${token_name},${token}" >> ${TOKEN_NAME_VALUE} fi done Omgewing generasie Volg asseblief die lêer terwyl ek verduidelik wat dit doen. Dit is belangrik sodat ons presies verstaan wat dit doen. Ons skep eers private en publieke sleutels in 'n formaat. Ons gebruik dan die private sleutel met ons hardloopbare "your-finance-jwt-generator.jar" . Dit is ons loopbare pot wat die vinnige skepping van tokens moontlik maak. Die uitreiker kan nie later verander word nie. Uiteindelik skep dit 'n teken. Ons sal later sien hoe om hierdie teken te lees. Hierdie teken bevat 3 ekstra Kop-eise. Dit is "kind", "typ" en "alg". Dit volg die volgende formaat: PEM { "kid": "jwt.key", "typ": "JWT", "alg": "RS256" } Die kop van die JWT Kom ons kyk van naderby na hierdie bewerings: "kind" - Werk as 'n wenk-eis. Dit dui aan watter soort algoritme ons gebruik. "typ" - Dit word gebruik om mediatipes te verklaar. Daar is drie opsies (JSON Web-token), (JSON Web Encryption), en (JSON Web Algorithms). Hierdie tipes is nie relevant vir ons eksperiment nie. Ons sal net sien dat ons teken nie regtig goed geïnkripteer is nie en dat dit regtig maklik is om dit te dekripteer. Ons sal ook sien dat alhoewel ons tokens kan dekripteer, ons nie so maklik kan peuter om ander aksies uit te voer nie. IANA JWT JWE JWA "alg" - Dit is hoe ons die handtekeningtipe definieer wat ons wil gebruik. Ondertekening kan beskou word as 'n kriptografiese operasie wat sal verseker dat die oorspronklike teken nie verander is nie en vertrou word. In ons geval gebruik ons RS256 andersins bekend as RSA Signature met SHA-256. Met ons publieke sleutel kan ons dit uiteindelik gebruik om ons sjabloon te verander. Die nuwe config.yml-lêer moet so lyk: kumuluzee: name: your-financeje-banking version: 1.0.0 jwt-auth: public-key: FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKE.FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETO.FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKEN issuer: joaofilipesabinoesperancinha healthy: true config.yml Die tweede stap is om vier lêers te skep. Vir elke enkele gewone token in die gids " ", sal ons vier opdragte skep. Die eerste opdrag is om gebruikers te skep wat effektief dinge met hul rekeninge kan doen. Dit is gebruikers met profiele " ", " " en " ". Kom ons hardloop die lêer " ", om hulle te skep. Die tweede opdrag sal die res van die gebruikers skep wat nog geen regte het nie. Dit is die lêer "createUser.sh". Kom ons bestuur dit. Nou sal ons sien dat alle gebruikers uiteindelik geskep is. Kom ons kyk nou na besonderhede oor transaksies en kyk na die oorblywende twee opdragte. Een om te "cashin" en 'n ander om meer krediet te vra. Die eerste gegenereerde lêer is die "sendMoney.sh" bash script. Hier kan ons alle versoeke vind om te " ". In hierdie lêer sal jy 'n krulversoek vind om ewekansige geldhoeveelhede per gebruiker aan gebruikers te stuur. Kom ons kyk na die admin saak: jwt-plain-tokens admin client credit createAccount.sh cashin #!/usr/bin/env bash # Send money to: admin echo -e "\e[93mSending money to \e[96madmin\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer= FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 125}' echo -e "\e[93m\n---\e[0m" # Send money to: cindy echo -e "\e[93mSending money to \e[96mcindy\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 360}' echo -e "\e[93m\n---\e[0m" # Send money to: faustina echo -e "\e[93mSending money to \e[96mfaustina\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 50}' echo -e "\e[93m\n---\e[0m" # Send money to: jack echo -e "\e[93mSending money to \e[96mjack\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 205}' echo -e "\e[93m\n---\e[0m" # Send money to: jitska echo -e "\e[93mSending money to \e[96mjitska\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 332}' echo -e "\e[93m\n---\e[0m" # Send money to: judy echo -e "\e[93mSending money to \e[96mjudy\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 295}' echo -e "\e[93m\n---\e[0m" # Send money to: lucy echo -e "\e[93mSending money to \e[96mlucy\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 160}' echo -e "\e[93m\n---\e[0m" # Send money to: malory echo -e "\e[93mSending money to \e[96mmalory\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 413}' echo -e "\e[93m\n---\e[0m" # Send money to: mara echo -e "\e[93mSending money to \e[96mmara\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 464}' echo -e "\e[93m\n---\e[0m" # Send money to: namita echo -e "\e[93mSending money to \e[96mnamita\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 51}' echo -e "\e[93m\n---\e[0m" # Send money to: pietro echo -e "\e[93mSending money to \e[96mpietro\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 491}' echo -e "\e[93m\n---\e[0m" # Send money to: rachelle echo -e "\e[93mSending money to \e[96mrachelle\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 474}' echo -e "\e[93m\n---\e[0m" # Send money to: sandra echo -e "\e[93mSending money to \e[96msandra\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 417}' echo -e "\e[93m\n---\e[0m" # Send money to: shikka echo -e "\e[93mSending money to \e[96mshikka\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/accounts -X PUT -d '{ "saldo": 64}' echo -e "\e[93m\n---\e[0m" sendMoney.sh uittreksel Dieselfde gebruikers het ook hul kredietversoeke aan hulle toegewys: #!/usr/bin/env bash # Asking money credit to: admin echo -e "\e[93mAsking credit from \e[96madmin\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 137}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: cindy echo -e "\e[93mAsking credit from \e[96mcindy\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 117}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: faustina echo -e "\e[93mAsking credit from \e[96mfaustina\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 217}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: jack echo -e "\e[93mAsking credit from \e[96mjack\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 291}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: jitska echo -e "\e[93mAsking credit from \e[96mjitska\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 184}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: judy echo -e "\e[93mAsking credit from \e[96mjudy\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 388}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: lucy echo -e "\e[93mAsking credit from \e[96mlucy\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 219}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: malory echo -e "\e[93mAsking credit from \e[96mmalory\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 66}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: mara echo -e "\e[93mAsking credit from \e[96mmara\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 441}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: namita echo -e "\e[93mAsking credit from \e[96mnamita\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 358}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: pietro echo -e "\e[93mAsking credit from \e[96mpietro\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 432}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: rachelle echo -e "\e[93mAsking credit from \e[96mrachelle\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 485}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: sandra echo -e "\e[93mAsking credit from \e[96msandra\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 500}' echo -e "\e[93m\n---\e[0m" # Asking money credit to: shikka echo -e "\e[93mAsking credit from \e[96mshikka\e[0m" curl -i -H'Content-Type: application/json' -H'Authorization: Bearer FAKE.FAKE.FAKE' http://localhost:8080/credit -X PUT -d '{ "saldo": 89}' echo -e "\e[93m\n---\e[0m" askCredit.sh uittreksel Al ons is deel van die Liga van . In wese net 'n groep mense om deel te wees van hierdie bankstelsel. In hierdie konteks verdedig hulle die omgewing. Dit is nie regtig relevant vir die artikel wat hierdie groep mense doen of waar in die storie hulle inpas nie, maar vir konteks neem hulle deel aan aksies om die omgewing te verdedig en die uitwerking van te vertraag. Sommige van ons kan alles doen, ander kan niks doen nie en ander kan net “cashin” of net “vra vir krediet”. Let ook op dat ek sensitiewe inligting vertroebel. Hierdie tekens moet normaalweg nie gedeel word of sigbaar wees op 'n spesifieke URL nie. Hulle is ja, altyd beskikbaar via die blaaier-ontwikkelaarkonsole, maar dit is in elk geval om sommige versoeke wat gemaak word, . Dit is 'n konsep wat bekend staan as "sekuriteit-per-duisternis" hoewel dit nie tegnies verhoed dat die gebruiker bewus word van die teken wat gebruik word nie, werk dit wel as 'n afskrikmiddel. In beide metodes, wanneer ons 'n deposito maak of wanneer ons vra vir krediet, let op dat ons vir elke versoek 'n ewekansige getal tussen 1 en 500 stuur. Ons is nou amper gereed om ons aansoek te begin, maar eers, laat ons 'n duik in 'n bietjie meer teorie neem. characters Nature klimaatsverandering characters protect and 10. Hoe word 'n token gemaak JWT Noudat ons ons tokens gegenereer het, kom ons kyk na een van hulle. Ek gaan vir jou 'n verduisterde teken wys, en ons gaan dit gebruik om dit te verstaan. Hier is ons teken: . . Wat hier belangrik is om op te let, is dat ons teken in drie dele verdeel is: FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKE FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETO FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKEN - Dit is 'n Base64-gekodeerde JSON-konfigurasie-kop, net soos ons hierbo bespreek het. Kop - Dit is 'n Base64-gekodeerde JSON-loonvrag. Dit is waar ons ons Gereserveerde en Pasgemaakte eise gedefinieer het. Ons kan hier ook Private en Openbare eise definieer. Beide van hulle val onder Custom eise. As 'n vinnige nota, kan ons doen wat ons wil met albei hierdie eise. Daar word egter na openbare eise verwys as dié wat in die IANA JSON Web Token Registry gedefinieer word. Dit is belangrik dat ons ons tokens op 'n sekere manier benoem om botsings met die register te vermy. Openbare eise kan ook as standaard opsioneel gedefinieer word. Private eise volg geen standaard nie en dit is aan ons om dit te definieer. Loonvrag - Dit is waar ons 'n bietjie kreatief kan wees. Die handtekening is 'n gesyferde kombinasie van die en die . Ons besluit die algoritme wat ons wil gebruik en hierdie deel van die teken sal basies bepaal of die boodskap wat ons stuur, vertrou moet word. Dit is uniek aan daardie kombinasie en ons bediener sal die "publieke sleutel" wat ons geskep het gebruik om te bepaal of ons 'n pasmaat het. As jy van bogenoemde onthou gebruik ons in ons voorbeeld. Handtekening Header Payload RS256 Voordat ons voortgaan, let asseblief daarop dat beide die en die in ons voorbeeld kan word. Ons "kan" net nie met die loonvrag of die kopstuk peuter en dit steeds vertrou nie. Die beskerming teen die potensiële gevolge van 'n kwaadwillige teken kan slegs beskerm word deur die algoritme wat ons kies. Kies dus verstandig. As jy in 'n organisasie werk waar hoogs geheime inligting 'n bekommernis is, soos 'n bank, MOET asseblief NIE doen wat ons gaan doen nie. Dit is slegs 'n manier vir ons om die inhoud van die tokens wat ons plaaslik gegenereer het aanlyn na te gaan. Kom ons gaan eers na en vul ons token in. Gebruik die teken wat jy pas gegenereer het: Header Payload decyphered https://jwt.io/ JWT Gebruik om die inhoud van ons teken na te gaan. Kom ons ondersoek wat ons hier het. Dit is ons administrateur-token. Daardie persoon is "Admin" in ons voorbeeld. Ons kan sien dat ons parameters almal beskikbaar is. In ons lys sien ons "sub", "aud", "upn", "access", "user_id", "iss", "name", "groups" en laastens die "jti". Ons het ook 'n paar ekstra eise. Kom ons kyk na hulle: https://jwt.io/ " " — Dit is wanneer die verifikasie plaasgevind het. Ons teken soos geverifieer op Sondag, 17 Julie 2022 16:15:47 GMT+02:00 DST" " — Dit is wanneer die teken geskep is. In ons geval gebeur dit gelyktydig as die auth_time." " - Dit is die vervaldatum van die teken. Dit verval op Sondag 17 Julie 2022 16:32:27 GMT+02:00 DST. Ons het geen vervaldatum in ons teken gespesifiseer nie. Dit beteken dat sy verstekwaarde van ~15 minute gebruik. auth_time iat exp JWT Kom ons doen nou 'n paar toetse. 11. Begin die toepassing Die kode is gereed om op gebruik te word. As ons die kode nagaan en dit met Intellij oopmaak, moet ons bewus wees dat ons nie hierdie toepassing soos 'n Spring Boot-toepassing kan laat loop nie. Daar is geen "psvm" om dit te laat loop nie. In plaas daarvan kan ons net die gegenereerde jar direk laat loop en seker maak dat ons net voor 'n "mvn build" maak. Hier is hoe ek dit op die oomblik gebruik: GitHub [ ] "Omgewingsopstelling om die toepassing te laat loop") https://github.com/jesperancinha/your-finance-je Laat ons nou weer die " "-skrip laat loop. Ek weet nie hoeveel tyd jy geneem het om hier te kom nie, maar dit is baie waarskynlik dat die 15 minute reeds verby is op hierdie stadium. Net vir ingeval, laat hulle net weer hardloop. Kom ons begin ons toepassing! Ons kan dit so begin: setupCertificates.sh mvn clean install java -jar your-financeje-banking/target/your-financeje-banking.jar Of ons kan dit net deur ons gereed-om-te-loop-konfigurasie laat loop. Gaan die repo en die Makefile vooraf na as jy alles wil verstaan wat dit doen: make dcup-full-action Hierdie skrip sal 2 dienste laat loop. Een op poort en die ander op poort . Op poort sal ons 'n weergawe van hierdie sagteware laat loop met ons eie kode om tokens te genereer. Op poort 8081 sal ons 'n weergawe gebruik met behulp van die kragopwekker geskep deur . Ons sal hierdie artikel egter fokus op die diens wat op poort loop. As jy wil, kan jy ook hardloop met: 8080 8081 8080 JWT jwtknizr Adam Bien 8080 cypress make cypress-open Dit sal die , en jy sal die toetse met die blaaier van jou keuse kan uitvoer. Blaaieropsies is egter steeds beperk op hierdie stadium. Die meeste van die versoeke sal eintlik opdragreëlversoeke wees wat deur verskaf word. Kom ons gaan vir eers nie na " " nie. Gaan asseblief na jou blaaier en gaan na hierdie ligging: cypress open cypress cypress http://localhost:8080/accounts/all Ons behoort 'n resultaat soos hierdie te kry: Soos ons kan sien, het " ", " " en " " geen krediet of geld nie. Dit is omdat hulle slegs die gebruikersgroep gegee is. Let ook op dat geen krediet gekry het nie. " ", is ons enigste kliënt wat nie die groepkrediet het nie. As ons na die logboeke kyk, kan ons sien dat suksesvolle bedrywighede hierdie formaat aanneem: Malory Jack Fallout Jitska Shikka Shikka Sending money to admin HTTP/1.1 200 OK Date: Sun, 17 Jul 2022 15:01:13 GMT X-Powered-By: KumuluzEE/4.1.0 Content-Type: application/json Content-Length: 32 Server: Jetty(10.0.9) {"balance":212,"client":"Admin"} 'n 200 laat ons weet dat die operasie suksesvol afgeloop het. In die geval van "Malory", "Jack Fallout" en "Jitska", misluk albei operasies en dan sal ons hierdie soort boodskap kry: Sending money to jitska HTTP/1.1 403 Forbidden X-Powered-By: KumuluzEE/4.1.0 Content-Length: 0 Server: Jetty(10.0.9) 'n 403 laat ons weet dat ons token bekragtig is en dat dit vertrou word. Die gebruiker word egter verbied om daardie operasie uit te voer. Met ander woorde, hulle het geen toegang tot die aangewese metode nie. JWT Kom ons peuter bietjie met ons tokens. As ons sommige van die tekens van die sendMoney.sh-lêer verander. Ons behoort hierdie te kry: Sending money to admin HTTP/1.1 401 Unauthorized X-Powered-By: KumuluzEE/4.1.0 WWW-Authenticate: Bearer realm="MP-JWT" Content-Length: 0 Server: Jetty(10.0.9) Gaan in volskermmodus Verlaat volskermmodus Hierdie beteken dat ons teken nie bekragtig is nie. Dit beteken dat die publieke sleutel wat die bediener gebruik om te kyk of ons token vertrou moet word, geen ooreenstemming gevind het nie. As die publieke sleutel nie die handtekening van die JWT-token kan evalueer en bekragtig nie, sal dit dit dan verwerp. 401 As 'n opsomming, die kopskrif en die "loonvrag" is nie geïnkripteer nie. Hulle is net basis 64 "geënkodeer". Dit beteken dat "Dekodering" ons altyd in staat stel om binne te kyk wat die loonvrag eintlik is. As ons soek om ons loonvrag te beskerm teen afluistering, moet ons nie die "Payload" van die teken vir enigiets anders gebruik as om identifikasieparameters te kies nie. Die probleem lê eintlik wanneer iemand die -token in die hande kry, byvoorbeeld wanneer die TLS-tonnel gekompromitteer is en iemand die inhoud van die uitgeruilde boodskappe kan lees. Wanneer dit gebeur, is daar nog 'n ander beskerming. En dit is die handtekening. Die enigste een wat 'n boodskap wat ingaan kan valideer, is die bediener wat die publieke sleutel bevat. Hierdie publieke sleutel, hoewel publiek, laat slegs toe om die inkomende boodskap te bekragtig deur teen die handtekening en die "Header + Payload" te hardloop. JWT 12. Gevolgtrekking Ons het die einde van ons sessie bereik. Dankie dat jy dit volg. Ons kan sien hoe -tokens kompak en baie minder breedvoerig is as hul XML-eweknie, die -tokens. Ons het gesien hoe maklik dit is om tokens te skep en te gebruik om sekere magtigings te kry wat nodig is vir sekere metodes en hoe ons daar kom via 'n getekende token. Ek vind egter baie belangrik om 'n idee te kry van hoe werk. Hopelik het ek hiermee vir jou 'n goeie inleiding gegee oor hoe -tokens werk. Om 'n beter idee te kry van hoe dit alles werk, raai ek jou aan om rond te speel met die geïmplementeerde . Dit is 'n goeie manier om te sien hoe versoeke gemaak word en wat ons toets en wat verwag word. Dan sal jy ook 'n beter idee kry van hoekom sommige gebruikers sekere bewerkings kan uitvoer en ander nie. Ek het al die bronkode van hierdie toepassing op geplaas. Ek hoop dat jy hierdie artikel soveel geniet het as wat ek dit geniet het om te skryf dit. Dankie dat jy gelees het! JWT SAML JWT JWT cypress GitHub 13. Verwysings Eclipse MicroProfile JWT Authentication API MicroProfile JSON Web Token (JWT) JSON Web Token Eise Kumuluz Blog kumuluzEE REST API Sekuriteit RUSvolle API-sekuriteit Tutoriaal: Skep en verifieer JWT's in Java oktadeveloper/okta-java-jwt-voorbeeld Spring Boot CLI Java EE Security API (JSR 375/Soteria) met JWT-tokens payara/Payara-voorbeelde Beveilig JAX-RS eindpunte met JWT Beveilig jou aansoek met Eclipse MicroProfile JWT Auth JWT Dispenser Konfigureerbare tekenverval 4.0.0 Mikrodienste met KumuluzEE MicroProfile 1.2 JWT-verifikasie: Wanneer en hoe om dit te gebruik Die uiteindelike gids vir die hantering van JWT's op frontend-kliënte (GraphQL) IANA JSON Web Token (JWT) CyberChef Gebruik KumuluzEE Security 'n Eenvoudige Engelse inleiding tot JSON-webtokens (JWT): wat dit is en wat dit nie is nie Internet Engineering Taakmag RFC7519