आजकल, हामी प्रदर्शन को बारे मा अधिक र अधिक चिन्ता छ, र एकै समयमा, हामी जान्न चाहन्छौं कि प्रणालीहरु कसरी छिटो र भरपर्दो संचार गर्न सक्छन्। धेरै पटक हामी जानकारी पठाउन र सकेसम्म गोप्य र सुरक्षित राख्न चाहन्छौं। संवेदनशील डेटा कहिलेकाहीँ सार्वजनिक रूपमा वेब मार्फत सार्न र तारको अर्को छेउमा कार्यहरू ट्रिगर गर्नुपर्छ। प्रायः, हामी कार्यहरू उत्पन्न गर्न चाहन्छौं जसले डेटा उत्परिवर्तनको कारण हुनेछ। यी मामिलाहरूमा, हामी केवल हाम्रो डाटा सुरक्षित गर्न हेरिरहेका छैनौं। हामी यो सुनिश्चित गर्न चाहन्छौं कि हाम्रो डाटा पठाएर ट्रिगर गरिएका कार्यहरू विश्वसनीय छन्। हामी हाम्रो डाटालाई धेरै तरिकामा सुरक्षित गर्न सक्छौं। सामान्यतया, हामी डेटा TLS
(ट्रान्सपोर्ट लेयर सेक्युरिटी) सुरक्षित जडान मार्फत पठाउँछौं। यसले सुनिश्चित गर्नेछ कि हाम्रो डाटा तार मार्फत इन्क्रिप्टेड हुन्छ। हामी दुई पक्षहरू बीच विश्वास गर्ने सम्बन्धहरू सिर्जना गर्न र यसलाई प्राप्त गर्न प्रमाणपत्रहरू प्रयोग गर्छौं। यस लेखमा, म JWT
मानकको बारेमा छलफल गर्न चाहन्छु र थप हेर्नुहोस् कि हामी कसरी JWT
साझा Enterprise
अनुप्रयोगमा एकीकृत गर्न सक्छौं। यस अवस्थामा, हामी KumuluzEE
मा एक नजर राख्नेछौं। केही आधारभूत अवधारणाहरू हेरौं। JWT
वा JSON वेब टोकन, वा अझ राम्रो, JavaScript वस्तु नोटेशन वेब टोकन, RFC7519 मा परिभाषित मानक हो। यो मानक, सबै RFC
(टिप्पणीहरूको लागि अनुरोध) मापदण्डहरू जस्तै, IETF
(Internet Engineering Task Force) द्वारा परिभाषित, लिखित र प्रकाशित गरिएको छ। यसलाई धेरै तरिकामा परिभाषित गर्न सकिन्छ। सामान्यतया, हामी भन्न सक्छौं कि JWT
दुई पक्षहरू बीच दावीहरू प्रसारण गर्ने एक संकुचित, सुरक्षित रूप हो। दावी के हो भनेर सरल बनाउने एउटा तरिका, मूलतया यसलाई जानकारी समावेश गर्ने नाम/मान जोडीको रूपमा वर्णन गर्नु हो। हामीलाई हाम्रो इन्टरनेट सञ्चारका केही महत्त्वपूर्ण पक्षहरूको ग्यारेन्टी गर्न यो जानकारी चाहिन्छ। हामीले यो सुनिश्चित गर्न आवश्यक छ कि हामीले प्राप्त गरेको जानकारी पहिलो उदाहरणमा मान्य र विश्वसनीय छ। त्यसपछि हामीले यसलाई प्रमाणीकरण गर्न आवश्यक छ। यो मूल रूपमा यो हो। यो मानक लागू गर्नको लागि, हामी धेरै फ्रेमवर्कहरू प्रयोग गर्न सक्छौं जसले हामीलाई जाभा इन्टरप्राइज अनुप्रयोग लागू गर्न मद्दत गर्न सक्छ। वसन्त बुट व्यापक रूपमा प्रयोग भइरहेको छ। धेरै पटक यो बैंकहरू र अन्य वित्तीय संस्थाहरू जस्ता निश्चित संस्थाहरूबाट प्रोप्राइटी सफ्टवेयरमा अर्को नाममा बेरिएको पनि हुन्छ। हाम्रो उदाहरणको लागि, मैले केहि फरक गर्ने निर्णय गरें। वसन्त बुट को सट्टा, हामी KumuluzEE
संग एक उदाहरण हेर्न जाँदैछौं। बिन्दु भनेको JWT
के हो र यो कस्तो देखिन्छ भनेर ठ्याक्कै पहिचान गर्नु हो। जाभा इन्टरप्राइज एप्लिकेसनहरू मूलतया एप्लिकेसन सर्भरमा डिप्लोय गर्न सकिने वा एम्बेडेड सर्भरको प्रयोग मार्फत आफैं चलाउन सकिने एपहरू हुन्। उदाहरणको रूपमा, वसन्त बुट अनुप्रयोगहरू एम्बेडेड टमक्याट सर्भरमा चल्छन्। यस लेखमा, हाम्रो फोकस KumuluzEE
मा सेट गरिनेछ। वसन्त बुट जस्तै यो पनि एक एम्बेडेड सर्भर समावेश गर्दछ। त्यो बाहेक यस अवस्थामा यसलाई जेट्टी भनिन्छ। यो CDI (सन्दर्भ निर्भरता इंजेक्शन) प्रदान गर्न वेल्ड संग संयोजन मा प्रयोग गरिन्छ। सबै Java EE
र Jakarta EE
टेक्नोलोजी मापदण्डहरू यस framework
उपयुक्त छन्।
JWT
कसरी यसको आधारभूत रूपमा काम गर्दछ उदाहरणको लागि, मैले यसलाई प्रस्तुत गर्ने तरिकाको बारेमा सोच्नुपरेको थियो। उत्कृष्ट उदाहरणहरू जहाँ सुरक्षा चिन्ताको विषय हो बैंकहरू। यद्यपि, JWT
कसरी काम गर्दछ भनेर देखाउनको लागि पूरै बैंक अनुप्रयोग बनाउनु समयको बर्बादी हुनेछ र हुनसक्छ धेरै अवधारणाहरू समावेश हुनेछन्। बरु, मैले बनाएको धेरै सरल बैंकिङ प्रणाली हो। हाम्रो मुख्य चासो तारबाट कसरी डाटा प्रवाह हुन्छ र प्रयोगकर्ताहरूले हाम्रो अनुप्रयोगको निश्चित क्षेत्रहरूमा कसरी पहुँच पाउँछन् भनेर देखाउनु हो। म पनि TLS वा कसरी हामी तार मार्फत इन्क्रिप्टेड जानकारी पठाउन सक्छौं भनेर छलफल गर्न जाँदैछु। हामी हाम्रो ध्यान JWT
मा यसको शुद्ध रूप मा राख्नेछौं। हाम्रो मामला एक बैंकिंग प्रणाली हो जुन प्रकृति र वातावरण को रक्षा गर्ने समूह द्वारा प्रयोग गरिन्छ। यो JWT
कसरी काम गर्दछ भनेर देखाउने एक रमाइलो तरिका हो। यस लीग अफ नेचरको मुख्य पात्र लुसी हो, जो मेरा सबै लेखहरूमा साझा पात्र बन्दैछ।
हामीले सुरु गर्नु अघि, हाम्रो चलिरहेको अनुप्रयोगलाई स्केच गरौं। यो एक धेरै सरल अनुप्रयोग हो, तर यो अझै पनि यसलाई आकर्षित गर्न राम्रो कुरा हो:
यो यति सरल हुनुको कारण यो हो कि JWT
प्रत्येक अनुरोधमा जाँच गरिन्छ र प्रत्येक अनुरोध सार्वजनिक कुञ्जी विरुद्ध प्रमाणित हुन्छ, त्यसोभए हामीलाई थाहा छ कि जबसम्म हामीले प्रत्येक अनुरोधमा सही टोकन पठाउछौं हामी प्राप्त गर्न सक्षम हुनेछौं। JWT
OAuth2, Okta SSO, वा कुनै अन्य प्राधिकरण संयन्त्रसँग एकीकृत गर्न सकिन्छ। यस अवस्थामा, हामीले प्रमाणीकरण र प्राधिकरण स्थापना गर्दैछौं। हाम्रो अनुप्रयोगमा, हामी JWT
प्रयोग गर्न जाँदैछौं र यसको साथ, हस्ताक्षर प्रयोग गरेर हाम्रो सन्देश प्रमाणीकरण गर्नुहोस्। यद्यपि हामी अनुप्रयोगमा लग इन गर्ने छैनौं। यसको सट्टा, हामी प्रयोगकर्ताहरूलाई सफल प्रमाणीकरण पछि हाम्रो अनुप्रयोग प्रयोग गर्न अधिकृत गर्नेछौं। यस बिन्दुमा, यो हेर्न सजिलो छ कि JWT
यसको कोरमा वास्तवमा पूर्ण अनुप्रयोगको धेरै सानो अंश हो। जे होस्, केही कार्यक्षमता थप्न आवश्यक छ। हामीलाई चाहिने स्रोतहरू यी हुन्:
हाम्रो आधारभूत प्रणालीले पैसा र क्रेडिट अनुरोधहरू मात्र दर्ता गर्नेछ भनेर भनौं। अनिवार्य रूपमा यसले केवल मानहरू जम्मा गर्नेछ। यो पनि मानौं कि केहि व्यक्तिहरूले क्रेडिट प्राप्त गर्न सक्षम हुनेछन् र अरूले गर्दैनन्। केही मानिसहरू पैसा भण्डारण गर्न सक्षम हुनेछन् र अरू मानिसहरूले क्रेडिट प्राप्त गर्न सक्षम हुनेछन्।
परिचयमा उल्लेख गरिएझैं, हामी KumuluzEE
हाम्रो इन्टरप्राइज एप्लिकेसन ढाँचाको रूपमा प्रयोग गर्नेछौं, र हामीले आधारभूत JWT
शब्दावली र अवधारणाहरू हेर्न सक्ने तरिकामा हामी अल्ट्रा-आधारभूत अनुप्रयोग लागू गर्नेछौं। सही Java संस्करण छ भनी सुनिश्चित गर्नुहोस्। यस चरणमा, हामीलाई न्यूनतम Java 17 SDK स्थापना आवश्यक पर्दछ। हामीलाई maven, git, जाभा-कम्प्याटिबल IDE जस्तै IntelliJ, र कुनै प्रकारको शेल चाहिन्छ।
हाम्रो आवेदन सुरु गर्नको लागि, हामीसँग केहि KumuluzEE
निर्भरताहरू छन्। यो मुख्यतया किनभने KumuluzEE
, वसन्त बुट जस्तै केहि निर्भरता को आवश्यकता छ। POM फाइललाई छोटकरीमा हेरौं:
<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>
केही निर्भरताहरू संक्षिप्त रूपमा छलफल गरौं। तपाईंले यो पढ्दा, कृपया हाम्रो pom.xml
फाइललाई माथिदेखि तलसम्म पछ्याउनुहोस्। निम्न स्पष्टीकरण बुझ्नको लागि यो महत्त्वपूर्ण छ। हाम्रो आवेदन काम गर्नको लागि हामीलाई निर्भरताहरूको प्याकेज चाहिन्छ। , सौभाग्य देखि, KumuluzEE
, हामीलाई माइक्रोप्रोफाइल पुस्तकालयहरू प्रदान गर्दछ जसमा यो अनुप्रयोग सुरु गर्न आधारभूत मानक बन्डलहरू छन्। यो सबै KumuluzEE
-Microprofile पुस्तकालय मा निहित छ। हामीलाई चाहिने सबै JWT
प्यारामिटरहरूसँग हाम्रो एप कन्फिगर गर्न सक्षम हुनको लागि, हामीले यसमा माइक्रोप्रोफाइल लाइब्रेरी थप्नु पर्छ। एकै समयमा, हामीलाई JSON प्रशोधन पुस्तकालय चाहिन्छ। यो जॉनसन कोरले के गर्छ। हामीलाई पक्कै पनि KumuluzEE
को कोर काम गर्न आवश्यक छ। जेट्टी अन्तर्निहित सर्भर हो जसले KumuluzEE
फ्रेमवर्क चलाउँछ। यसैले हामीलाई हाम्रो निर्भरतामा यो चाहिन्छ। हामीलाई CDI
चाहिन्छ भनेर विचार गर्दै, हामीलाई यसलाई समर्थन गर्ने पुस्तकालय पनि चाहिन्छ। हाम्रो REST अन्त्य बिन्दुहरू सक्षम गर्नको लागि, हामीलाई KumuluzEE
को बाँकी पुस्तकालय चाहिन्छ। हाम्रो API प्राप्त गर्नको लागि, हामीलाई त्यसपछि Geronimo पुस्तकालय चाहिन्छ। यसले सुनिश्चित गर्नेछ कि हामीसँग JSR-374
को कार्यान्वयन उपलब्ध छ। हामीले हाम्रो JWT
र यसको JSON-formatted
सामग्रीहरू पनि व्याख्या गर्न आवश्यक छ। Lombok वास्तवमा प्रति se आवश्यक छैन। यसले केवल सबै चीज सुन्दर र चमकदार बनाउँछ! लगब्याक हुनु पनि महत्त्वपूर्ण छ ताकि हामी लगहरूलाई राम्रोसँग व्याख्या गर्न र हाम्रा नतिजाहरू बुझ्न सक्छौं। अब हाम्रो resources
फोल्डरमा एक नजर राखौं। सुरु गर्नको लागि पहिले हामी यो फोल्डरमा के फेला पार्ने आशा गर्छौं भनेर बुझौं। हामीले हाम्रो एप्लिकेसनलाई JWT
, लगब्याकसँग सम्बन्धित केहिसँग कन्फिगर गर्न आवश्यक छ र अन्तमा, हामीले सिर्जना गर्न लागेका बीन्सको बारेमा केही भन्न आवश्यक छ। त्यहाँको सबैभन्दा सरल फाइल हेरौं। beans.xml META-INF मा फेला पार्न सकिन्छ:
<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>
यो केवल एक सामान्य हो र तपाईं अहिले सोच्दै हुनुहुन्छ, पुरानो फाइल को एक बिट। यस बिन्दुमा, विचार 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>
यो हाम्रो logs
को लागी एक धेरै सीधा कन्फिगरेसन हो।अन्तमा, हाम्रो आवेदन को सबैभन्दा महत्त्वपूर्ण फाइल हुन सक्छ। यो कन्फिगरेसन टेम्प्लेट हो। यस बिन्दुमा, यो नोट गर्न महत्त्वपूर्ण छ कि मैले यस परियोजनामा सिर्जना गरेका केही फाइलहरू टेम्प्लेट संरचनाको अंश हुन्। म पछि यसको बारेमा थप व्याख्या गर्नेछु। यो टेम्प्लेट फाइल config.yml फाइलमा परिणत भएको मानिन्छ जुन माइक्रोप्रोफाइलले पढ्ने छ। यो फाइल स्रोतहरूको मूलमा अवस्थित छ:
kumuluzee: name: your-financeje-banking version: 1.0.0 jwt-auth: public-key: {{ publicKey }} issuer: {{ issuer }} healthy: true
हामी पछि हेर्नेछौं कि यी सबै गुणहरूको वास्तवमा के मतलब छ। ती सबै आत्म-व्याख्यात्मक छन्। सार्वजनिक कुञ्जी र जारीकर्ता सबै प्यारामिटरहरू हुन् जुन प्रतिस्थापन गरिनेछ। हामी यसलाई पछि अन्वेषण गर्नेछौं। हाम्रो bash स्क्रिप्टहरूले तिनीहरूलाई प्रतिस्थापन गर्न सुनिश्चित गर्नेछ। हामी कोडिङमा जान लगभग तयार छौं, तर पहिले, हाम्रो JWT
टोकन संरचनालाई हेरौं।
हाम्रो धेरै सानो अनुप्रयोग बनाउनुहोस्। यस खण्डले हामी कसरी 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" }
हाम्रो JSON
मा यी नामहरू मध्ये प्रत्येकलाई दावी भनिन्छ। हाम्रो उदाहरणमा, हामी केही आरक्षित दावीहरू देख्छौं:
iss
" — यो टोकन जारीकर्ता हो। हामी मनमानी रूपमा यसको लागि एक मूल्य छनोट गर्न सक्छौं। यस प्यारामिटरको मान हामीले पहिले देखेको config.yml मा प्रतिस्थापन गर्न जारीकर्ता चरसँग मेल खानुपर्छ।jti
" - यो टोकन को एक अद्वितीय पहिचानकर्ता हो। हामी उदाहरणका लागि टोकनलाई दुई वा बढी पटक प्रयोग हुनबाट रोक्न यो दाबी प्रयोग गर्न सक्छौं।sub
" - यो टोकनको विषय हो। यो प्रयोगकर्ता वा हामीलाई मनपर्ने केहि पनि हुन सक्छ। यो ध्यानमा राख्नु महत्त्वपूर्ण छ कि यसलाई पहिचानकर्ता, कुञ्जी, नामकरण, वा हामीले चाहेको कुराको रूपमा पनि प्रयोग गर्न सकिन्छ।upn
" - प्रयोगकर्ता प्रमुख नाम। यो प्रयोगकर्ताले प्रयोग गरिरहेको प्रिन्सिपल पहिचान गर्न प्रयोग गरिन्छ।groups
" — यो हालको प्रयोगकर्तासँग सम्बन्धित समूहहरूको एर्रे हो। अनिवार्य रूपमा यसले निर्धारण गर्नेछ कि यो टोकनको साथ अनुरोधले के गर्न सक्छ। हाम्रो टोकनमा, हामी त्यसपछि केही अनुकूलन दावीहरू देख्छौं। हामी यसलाई आरक्षित दावीहरू जस्तै प्रयोग गर्न सक्छौंuser_id
" - हामी यसलाई प्रयोगकर्ता आईडी सेट गर्न प्रयोग गर्नेछौं।access
" - हामी प्रयोगकर्ताको पहुँच स्तर निर्धारण गर्नेछौं।name
" - प्रयोगकर्ताको नाम। हामीले अहिलेसम्म के थाहा पाएको छ त्यसको पुनरावृत्ति गरौं। हामीलाई थाहा छ कि हामीले निर्धारण गरेका ढाँचाका साथ टोकनहरूसँग कुराकानी गर्नेछौं। यसबाहेक, हामीले हाम्रो एप्लिकेसनको कन्फिगरेसन, लगब्याक कन्फिगरेसन सेटअप गरेका छौं र अन्तमा, हामीले इन्टरप्राइज बीन लुकअपको लागि अनुकूलन कन्फिगरेसन सेट अप गर्यौं। प्याकेज मोडेल हेरौं। यहाँ हामी 3 कक्षाहरू फेला पार्नेछौं। यी वर्गहरूले मूल रूपमा खाताहरूको एकीकरण र client
र account
बीचको प्रतिनिधित्वलाई प्रतिनिधित्व गर्दछ। यस तरिकाले हामी kotlin फाइल Model.kt हेरेर सुरु गर्न सक्छौं जहाँ Client
अवस्थित छ:
data class Client constructor( @JsonProperty var name: String ?= null )
यो पहिलो मोडेल वर्ग हाम्रो ग्राहक को प्रतिनिधित्व हो। हाम्रो केसको लागि हाम्रो 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)) ) }
यस कक्षामा, हामीले मूल रूपमा एक खाता नम्बर, ग्राहक, हालको मूल्य र अन्तमा क्रेडिट मूल्य सेट अप गर्छौं। ध्यान दिनुहोस् कि हामी सबै मानहरू ० मा पूर्वनिर्धारित गर्दैछौं। हामीले पनि BigDecimal प्रयोग गरिरहेका छौं, विशुद्ध रूपमा किनभने हामी पैसासँग व्यवहार गरिरहेका छौं। पैसा सही हुनुपर्छ र प्रणाली राउन्ड-अप वा राउन्ड-डाउनहरू भोग्न सक्दैन। यसको मतलब अर्को शब्दमा र उदाहरणको रूपमा ०. 0000000000000000000000000000000000000000000000000001
यूरोजस्तै त्यो संख्या सधैँ रहनुपर्छ भन्ने हो। साथै, हामी हाम्रो खातामा मानहरू थप्न चाहन्छौं। यो जहाँ विधि addCurrentValue अवस्थित हुन्छ। उही कारणहरूका लागि, हामी addCreditValue
सँग हाम्रो क्रेडिट पनि माथि गर्नेछौं। अन्तमा, हाम्रो डेटा सेटअपको अन्तिम टुक्रामा हामी वर्ग Accounts
भेट्छौं:
open class Accounts constructor( open val accountMap: MutableMap<String, Account> = mutableMapOf() )
यो अनिवार्य रूपमा हाम्रो सबै खाताहरूको एक एग्रीगेटर हो। हामी डाटाबेसको व्यवहारको नक्कल गर्न यसको नक्सा सामग्री प्रयोग गर्नेछौं। अब नियन्त्रक प्याकेज हेरौं। यो जहाँ हामी हाम्रो डाटा मोडेल संग चलिरहेको हाम्रो अनुप्रयोग सिर्जना गर्छौं। पहिले, कक्षा BankApplication
मा एक नजर राखौं:
@LoginConfig(authMethod = "MP-JWT") @ApplicationPath("/") @DeclareRoles("admin", "creditor", "client", "user") class BankApplication : Application()
यससँगै हामीले ३ महत्वपूर्ण कुराहरु भनिरहेका छौं । LoginConfig एनोटेसनको साथ, हामी यसलाई माइक्रोप्रोफाइल अनुसार JWT
टोकनहरू प्रयोग गर्न र बुझ्नको लागि परिभाषित गर्छौं। ApplicationPath ले एप्लिकेसन रूट परिभाषित गर्दछ। यो जहाँ अनुप्रयोगको URL सुरु हुनेछ। हाम्रो उदाहरणमा, यो HTTP://localhost:8080 हुनेछ। अन्तमा, DeclareRoles ले हाम्रो एप्लिकेसनद्वारा प्रयोग र स्वीकृत हुने भूमिकाहरूलाई परिभाषित गर्दछ। भूमिका र समूहहरू यस अवस्थामा आदानप्रदान योग्य सर्तहरू हुन्। इन्जेक्सनले प्रभावकारी रूपमा काम गर्नको लागि, हामी खाता नक्सा पहिचान गर्नको लागि विशिष्ट एनोटेसन सिर्जना गर्छौं:
annotation class AccountsProduct
फुलस्क्रिन मोडमा प्रवेश गर्नुहोस् फुलस्क्रिन मोडबाट बाहिर निस्कनुहोस्
अर्को, हामी क्यास वस्तु कारखाना 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() } } }
यो फ्याक्ट्रीको कारणले गर्दा हामीले Accounts
लागि विशेष रूपमा लुकअप असक्षम गर्यौं। लुकअप प्रक्रियालाई बीन सिर्जना गर्न अनुमति दिनुको सट्टा, हामी आफैंले एग्रीगेटर उदाहरण सिर्जना गर्छौं। उत्पादन एनोटेशन प्रयोग गरेर, हामीलाई बीन सिर्जना गर्न अनुमति दिन्छ। हाम्रो अनुकूलन एनोटेसन, AccountsProduct प्रयोग गरेर, हामी यस बीनको प्रयोगलाई थप विशिष्ट बनाउँछौं। अन्तमा, ApplicationScoped
प्रयोग गरेर, हामी यसको दायरालाई Application
स्कोपको रूपमा परिभाषित गर्छौं। अर्को शब्दमा भन्नुपर्दा, खाता एग्रीगेसन बीनले एप्लिकेसनमा सिंगलटन वस्तुको रूपमा व्यवहार गर्नेछ। " createResponse
" JSON प्रतिक्रियाहरू सिर्जना गर्ने एउटा सामान्य विधि मात्र हो। हामीलाई अहिले दुईवटा "संसाधनहरू" चाहिन्छ। यो मूलतः वसन्तमा " 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) } }
यस कक्षालाई विस्तृत रूपमा हेर्नको लागि एक क्षण लिनुहोस्। Path
एनोटेशनले यो स्रोतलाई रूटबाट कसरी पुग्ने भनेर परिभाषित गर्दछ। याद गर्नुहोस् कि हामीले रूटको रूपमा "/" प्रयोग गर्दैछौं। यस अवस्थामा, "खाताहरू" यस स्रोतको लागि हाम्रो मूल पहुँच बिन्दु हो। हाम्रा सबै रिसोर्सहरू, हाम्रो केसमा दुई मात्र स्कोप अनुरोध रिसोर्ससँग चलिरहेका छन्। एनोटेसन प्रोडक्सेसले निर्धारण गर्दछ कि सबै अनुरोधहरूको सबै प्रतिक्रियाहरू तिनीहरूको प्रकारको वास्ता नगरी JSON ढाँचा गरिएका सन्देशहरूको रूपमा लिनेछन्। हाम्रो aggregator
इन्जेक्ट गर्न हामी केवल इन्जेक्ट एनोटेसन र AccountsProduct
एनोटेसनको संयोजन प्रयोग गर्छौं:
@Inject @AccountsProduct open var accounts: Accounts? = null
यो हामीले कारखानामा परिभाषित गरेको कुरासँग मेल खान्छ। यसबाहेक, हामी सुरक्षाका दुई महत्त्वपूर्ण तत्वहरू पनि इन्जेक्ट गर्दैछौं। एक principal
र jsonWebToken
:
@Inject open var principal: Principal? = null @Inject open var jsonWebToken: JsonWebToken? = null
JsonWebToken
र Principal
दुवै समान हुनेछन्, र हामी हाम्रो लगहरूमा देख्नेछौं। हाम्रो स्रोतहरूमा, हामी सधैँ एक निश्चित टोकनको साथ अनुरोधबाट दावीहरू इन्जेक्ट गर्न सक्छौं:
@Inject @Claim("name") open var name: JsonString? = null @Inject @Claim("user_id") open var userId: JsonNumber? = null
यो Inject
र Claim
एनोटेशन को संयोजन संग पूरा भएको छ। Claim
एनोटेसन अन्तर्गत राखिएको नामले कुन दावीलाई हामी सुई दिन चाहन्छौं भनेर परिभाषित गर्दछ। हामीले हाम्रो प्यारामिटरहरू परिभाषित गर्ने प्रकारसँग सावधान रहनुपर्छ। हाम्रो उदाहरणमा, r हामीलाई 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() ) ) }
खाता र प्रयोगकर्ताहरू सिर्जना गर्दै
यहाँ उद्देश्य विधिहरू अलग गर्न र तिनीहरूलाई फरक अनुमति दिन सक्षम हुनु हो। हाम्रो उदाहरणमा, तिनीहरू दुवैले मात्र खाता सिर्जना गर्छन्, तर यो ध्यान दिन महत्त्वपूर्ण छ कि भूमिका प्रयोगकर्ताहरूले मात्र CreateUser विधि प्रयोग गर्न सक्छन्। त्यसै गरी, ग्राहक र क्रेडिटको भूमिका भएका प्रयोगकर्ताहरूले CreateAccount विधिमा पहुँच गर्न सक्छन्। अब यस स्रोतको PUT अनुरोध विधिमा विस्तृत रूपमा हेरौं:
@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) }
नगद इन
हामीलाई थाहा छ कि एनोटेसन PUT
संकेत गर्दछ कि यो विधि PUT
प्रकारका अनुरोधहरूमा मात्र पहुँचयोग्य छ। एनोटेसन पथले जेट्टीलाई बताउँछ कि यो विधिको बाटो मान हो। यसलाई PathParam
पनि भनिन्छ। अन्तमा, हामी यो विधिलाई व्यवस्थापक वा ग्राहकको भूमिका भएका प्रयोगकर्ताहरूद्वारा मात्र प्रयोग गर्न अनुमति दिइन्छ भनेर परिभाषित गर्न सक्छौं। इनपुट मान त्यसपछि 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) } }
फरक यति मात्र हो कि भूमिकाहरू admin
र client
प्रयोग गर्नुको सट्टा हामी अब admin
र credit
भूमिकाहरू प्रयोग गर्दैछौं। साथै, ध्यान दिनुहोस् कि यस resource
प्रयोगकर्ताहरूको लागि खाताहरू कहिल्यै सिर्जना गरिने छैन। यो खाताको resource
मार्फत मात्र सम्भव छ। अब हामीले कोड कसरी लागू हुन्छ भन्ने थाहा पाएपछि हामीले हाम्रो REST
सेवामा कुन-कुन विधिहरू उपलब्ध गराएका छौं भनेर पहिले सम्झौं।
प्रयोग भइरहेको सेवाहरूको सूची जाँच गरौं:
टाइप, URL, पेलोड, नतिजा, भूमिकाहरूलाई अनुमति दिइएको छ
पोस्ट,
पोस्ट,
प्राप्त गर्नुहोस्,
राख्नुहोस्,
प्राप्त गर्नुहोस्,
प्राप्त गर्नुहोस्,
प्राप्त गर्नुहोस्,
राख्नुहोस्,
प्राप्त गर्नुहोस्,
प्राप्त गर्नुहोस्,
मैले रूट फोल्डरमा bash
फाइल सिर्जना गरेको छु। यो फाइल "setupCertificates.sh" भनिन्छ। यसले के गर्छ भन्ने बारे एक विचार पाउनको लागि यसलाई हेरौं:
#!/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
वातावरण उत्पादन
कृपया फाइललाई पछ्याउनुहोस् जसरी मैले यो के गर्छ भनेर व्याख्या गर्नुहोस्। यो महत्त्वपूर्ण छ कि हामीले यो के गरिरहेको छ भन्ने कुरा बुझ्नको लागि। हामीले पहिले PEM
ढाँचामा निजी र सार्वजनिक कुञ्जीहरू सिर्जना गर्छौं। त्यसपछि हामी हाम्रो चलाउन सकिने "your-finance-jwt-generator.jar" सँग निजी कुञ्जी प्रयोग गर्छौं। यो हाम्रो चलाउन योग्य जार हो जसले टोकनहरूको द्रुत सिर्जनाको लागि अनुमति दिन्छ। जारीकर्ता पछि परिवर्तन गर्न सकिँदैन। अन्तमा, यसले टोकन सिर्जना गर्दछ। हामी पछि यो टोकन कसरी पढ्ने भनेर हेर्नेछौं। यो टोकनमा ३ अतिरिक्त हेडर दाबीहरू छन्। यी "बच्चा", "टाइप", र "alg" हुन्। यो निम्न ढाँचा पछ्याउँछ:
{ "kid": "jwt.key", "typ": "JWT", "alg": "RS256" }
JWT
को हेडर
यी दावीहरूलाई अझ नजिकबाट हेरौं:
IANA
मिडिया प्रकारहरू घोषणा गर्न प्रयोग गरिन्छ। त्यहाँ तीन विकल्पहरू छन् JWT
(JSON वेब टोकन), JWE
(JSON वेब एन्क्रिप्शन), र JWA
(JSON वेब एल्गोरिदम)। यी प्रकारहरू हाम्रो प्रयोगसँग सान्दर्भिक छैनन्। हामी केवल हाम्रो टोकन वास्तवमै राम्रोसँग इन्क्रिप्ट गरिएको छैन र यसलाई डिक्रिप्ट गर्न साँच्चै सजिलो छ भनेर देख्नेछौं। हामी यो पनि देख्नेछौं कि यद्यपि हामी टोकनहरू डिक्रिप्ट गर्न सक्छौं, हामी अन्य कार्यहरू गर्न सजिलैसँग छेडछाड गर्न सक्दैनौं।हाम्रो सार्वजनिक कुञ्जीको साथ, हामी अन्ततः यसलाई हाम्रो टेम्प्लेट परिवर्तन गर्न प्रयोग गर्न सक्छौं। नयाँ config.yml फाइल यस्तो देखिनु पर्छ:
kumuluzee: name: your-financeje-banking version: 1.0.0 jwt-auth: public-key: FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKE.FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETO.FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKEN issuer: joaofilipesabinoesperancinha healthy: true
config.yml
दोस्रो चरण चार फाइलहरू सिर्जना गर्न हो। डाइरेक्टरी " jwt-plain-tokens
" मा प्रत्येक एकल सादा टोकनको लागि, हामी चार आदेशहरू सिर्जना गर्नेछौं। पहिलो आदेश भनेको प्रयोगकर्ताहरू सिर्जना गर्नु हो जसले प्रभावकारी रूपमा तिनीहरूको खाताहरूसँग काम गर्न सक्छ। यी प्रोफाइलहरू " admin
", " client
", र " credit
" भएका प्रयोगकर्ताहरू हुन्। तिनीहरूलाई सिर्जना गर्नको लागि फाइल " createAccount.sh
" चलाउनुहोस्। दोस्रो आदेशले बाँकी प्रयोगकर्ताहरू सिर्जना गर्नेछ जसमा अझै कुनै अधिकार छैन। यो "createUser.sh" फाइल हो। यसलाई चलाउन दिनुहोस्। अब हामी देख्नेछौं कि सबै प्रयोगकर्ताहरू अन्तमा सिर्जना भएका छन्। अब लेनदेनको बारेमा विवरणहरू हेरौं र बाँकी दुई आदेशहरू हेरौं। एउटा "क्यासिन" र अर्को थप क्रेडिटको लागि सोध्न। पहिलो उत्पन्न फाइल "sendMoney.sh" bash स्क्रिप्ट हो। यहाँ हामी " 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 निकासी
उही प्रयोगकर्ताहरूले उनीहरूको क्रेडिट अनुरोधहरू पनि उनीहरूलाई तोकेका छन्:
#!/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 एक्स्ट्र्याक्ट
हाम्रा सबै characters
लिग अफ Nature
अंश हुन्। यस बैंकिङ प्रणालीको हिस्सा हुन अनिवार्य रूपमा केही व्यक्तिहरूको समूह मात्र हो। यस सन्दर्भमा, तिनीहरू पर्यावरणको रक्षा गर्दैछन्। यो साँच्चै लेखको लागि सान्दर्भिक छैन कि मानिसहरूको यो समूहले के गर्छ वा कथामा तिनीहरू कहाँ फिट छन्, तर सन्दर्भको लागि, तिनीहरू वातावरणको रक्षा गर्न र जलवायु परिवर्तनको प्रभावहरूलाई सुस्त बनाउन कार्यहरूमा भाग लिन्छन्। हाम्रा केही characters
सबै गर्न सक्छन्, अरूले केही गर्न सक्दैनन् र अरूले "क्यासिन" वा "क्रेडिटको लागि सोध्नुहोस्" मात्र गर्न सक्छन्। यो पनि ध्यान दिनुहोस् कि म संवेदनशील जानकारी अस्पष्ट गर्दैछु। यी टोकनहरू सामान्यतया साझा गर्नु हुँदैन वा विशेष URL मा देखिनु हुँदैन। तिनीहरू हो सधैं ब्राउजर विकासकर्ता कन्सोल मार्फत उपलब्ध छन् तर जे भए पनि केही अनुरोधहरू protect
गर्न हो। यो "सुरक्षा-प्रति-अस्पष्टता" को रूपमा चिनिने अवधारणा हो and
यद्यपि यसले प्रयोगकर्तालाई टोकन प्रयोग भइरहेको बारे सचेत हुनबाट प्राविधिक रूपमा रोक्दैन, यसले अवरोधको रूपमा काम गर्छ। दुवै विधिहरूमा, हामीले जम्मा गर्दा वा जब हामी क्रेडिटको लागि सोध्नुहोस्, ध्यान दिनुहोस् कि प्रत्येक अनुरोधको लागि, हामी 1 देखि 500 को बीचमा अनियमित नम्बर पठाउँदैछौं। हामी अब हाम्रो आवेदन सुरु गर्न लगभग तयार छौं, तर पहिले, अलिकति डुब्नुहोस्। थप सिद्धान्त।
JWT
टोकन कसरी बनाइन्छ
अब हामीले हाम्रा टोकनहरू उत्पन्न गरेका छौं, ती मध्ये एउटालाई हेरौं। म तपाईंलाई एउटा अस्पष्ट टोकन देखाउन जाँदैछु, र हामी यसलाई बुझ्नको लागि प्रयोग गर्नेछौं। यहाँ हाम्रो टोकन छ: FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKE
। FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETO
। FAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKENFAKETOKEN
यहाँ ध्यान दिनको लागि के महत्त्वपूर्ण छ कि हाम्रो टोकन तीन भागहरूमा विभाजित छ:
Header
र Payload
साइफर्ड संयोजन हो। हामीले प्रयोग गर्न चाहेको एल्गोरिदमको निर्णय गर्छौं र टोकनको यो बिटले हामीले पठाएको सन्देशलाई विश्वास गर्ने हो कि होइन भनेर मूल रूपमा निर्धारण गर्नेछ। यो त्यो संयोजनको लागि अद्वितीय छ र हाम्रो सर्भरले हामीले बनाएको "सार्वजनिक-कुञ्जी" प्रयोग गर्नेछ कि हामीसँग मिल्दोजुल्दो छ कि छैन भनेर निर्धारण गर्न। यदि तपाइँ माथिबाट सम्झनुहुन्छ भने हामी हाम्रो उदाहरणमा RS256
प्रयोग गर्दैछौं।
हामीले जारी राख्नु अघि, कृपया ध्यान दिनुहोस् कि Header
र Payload
दुवै हाम्रो उदाहरणमा decyphered
गर्न सकिन्छ। हामी केवल पेलोड वा हेडरसँग छेडछाड गर्न सक्दैनौं र अझै पनि यसलाई विश्वसनीय बनाउँछौं। हानिकारक टोकनको सम्भावित प्रभावहरू विरुद्धको सुरक्षा हामीले रोजेको एल्गोरिदमद्वारा मात्र सुरक्षित गर्न सकिन्छ। त्यसैले बुद्धिमानी छनोट गर्नुहोस्। यदि तपाइँ कुनै संस्थामा काम गर्दै हुनुहुन्छ जहाँ शीर्ष गोप्य जानकारी चिन्ताको विषय हो, जस्तै बैंक, कृपया हामी के गर्न लागेका छौं नगर्नुहोस्। हामीले स्थानीय रूपमा उत्पन्न गरेका टोकनहरूको सामग्री अनलाइन जाँच गर्ने यो एउटा तरिका मात्र हो। पहिले, https://jwt.io/ मा जानुहोस् र हाम्रो JWT
टोकन भर्नुहोस्। तपाईंले भर्खरै उत्पन्न गर्नुभएको टोकन प्रयोग गर्नुहोस्:
हाम्रो टोकनको सामग्रीहरू जाँच गर्न https://jwt.io/ प्रयोग गरेर हामी यहाँ के छ भनेर जाँच गरौं। यो हाम्रो प्रशासक टोकन हो। त्यो व्यक्ति हाम्रो उदाहरणमा "प्रशासक" हो। हामी देख्न सक्छौं कि हाम्रा प्यारामिटरहरू सबै उपलब्ध छन्। हाम्रो सूचीमा हामी "sub", "aud", "upn", "access", "user_id", "iss", "name", "groups" र अन्तमा "jti" देख्छौं। हामीसँग केहि अतिरिक्त दावीहरू पनि छन्। तिनीहरूलाई हेरौं:
" auth_time " - यो हो जब प्रमाणीकरण भयो। हाम्रो टोकन आइतबार, १७ जुलाई २०२२ 16:15:47 GMT+02:00 DST " iat " मा प्रमाणीकरण गरिएको थियो — यो टोकन सिर्जना भएको बेला हो। हाम्रो अवस्थामा, यो auth_time को रूपमा एकैसाथ हुन्छ। exp " — यो टोकनको म्याद सकिने मिति हो। यसको म्याद आइतबार, १७ जुलाई २०२२ १६:३२:२७ GMT+०२:०० DST मा सकिन्छ। हामीले हाम्रो टोकनमा कुनै म्याद सकिने मिति निर्दिष्ट गरेका छैनौं। यसको मतलब JWT
~ 15 मिनेटको पूर्वनिर्धारित मान प्रयोग गर्दछ।
अब केही परीक्षण गरौं।
कोड GitHub मा प्रयोग गर्न तयार छ। यदि हामीले कोड जाँच गर्छौं र यसलाई Intellij मार्फत खोल्छौं भने हामी यो एपलाई स्प्रिङ बुट एप्लिकेसन जस्तै चलाउन सक्दैनौं भन्ने कुरामा सचेत हुनुपर्छ। यसलाई चलाउनको लागि त्यहाँ कुनै "psvm" छैन। यसको सट्टा, हामी केवल उत्पन्न जार सीधा चलाउन सक्छौं र निश्चित गर्नुहोस् कि हामीले पहिले "mvn बिल्ड" बनायौं। यहाँ यो छ कि म यो पल कसरी प्रयोग गर्दैछु:
[ ] https://github.com/jesperancinha/your-finance-je "एप्लिकेशन चलाउनको लागि वातावरण सेटअप")
अब फेरि " setupCertificates.sh
" स्क्रिप्ट चलाउनुहोस्। मलाई थाहा छैन तपाईले यहाँ पुग्न कति समय लिनुभयो तर यो धेरै सम्भव छ कि 15 मिनेट पहिले नै यस बिन्दुमा गइसकेको छ। यदि मात्र हो भने, तिनीहरूलाई फेरि चलाउनुहोस्।हाम्रो एप सुरु गरौं!हामी यसलाई यसरी सुरु गर्न सक्छौं:
mvn clean install java -jar your-financeje-banking/target/your-financeje-banking.jar
वा हामी यसलाई हाम्रो तयार-टु-गो चलिरहेको कन्फिगरेसन मार्फत चलाउन सक्छौं। रेपो र मेकफाइललाई पहिले नै जाँच गर्नुहोस् यदि तपाइँ यो गर्ने सबै कुरा बुझ्न चाहनुहुन्छ भने:
make dcup-full-action
यो स्क्रिप्टले २ सेवाहरू चलाउनेछ। एउटा पोर्ट 8080
मा र अर्को पोर्ट 8081
मा। पोर्ट 8080
मा हामी JWT
टोकनहरू उत्पन्न गर्न हाम्रो आफ्नै कोड चलाउने यो सफ्टवेयरको संस्करण चलाउनेछौं। पोर्ट 8081 मा, हामी Adam Bien
द्वारा बनाईएको jwtknizr
जेनेरेटर प्रयोग गरेर संस्करण चलाउनेछौं। हामी यस लेखलाई केन्द्रित गर्नेछौं, यद्यपि पोर्ट 8080
मा चलिरहेको सेवामा। यदि तपाइँ चाहनुहुन्छ भने, तपाइँ cypress
पनि चलाउन सक्नुहुन्छ:
make cypress-open
यसले cypress
कन्सोल open
, र तपाइँ तपाइँको मनपर्ने ब्राउजर संग परीक्षणहरू चलाउन सक्षम हुनुहुनेछ। यद्यपि, यस चरणमा ब्राउजर विकल्पहरू अझै सीमित छन्। धेरै जसो अनुरोधहरू वास्तवमा cypress
द्वारा प्रदान गरिएको कमाण्ड लाइन अनुरोधहरू हुनेछन्। अहिलेको लागि, " cypress
" मा नजाऔं। कृपया आफ्नो ब्राउजरमा जानुहोस् र यो स्थानमा जानुहोस्:
http://localhost:8080/accounts/all
हामीले यस्तो नतिजा पाउनु पर्छ:
हामी देख्न सक्छौं, " 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"}
A 200 ले हामीलाई थाहा दिन्छ कि अपरेशन सफलतापूर्वक भयो। "मालोरी", "ज्याक फलआउट", र "जित्सका" को अवस्थामा, दुबै अपरेशनहरू असफल हुन्छन् र त्यसपछि हामीले यस प्रकारको सन्देश प्राप्त गर्नेछौं:
Sending money to jitska HTTP/1.1 403 Forbidden X-Powered-By: KumuluzEE/4.1.0 Content-Length: 0 Server: Jetty(10.0.9)
A 403 ले हामीलाई थाहा दिन्छ कि हाम्रो JWT
टोकन प्रमाणीकरण गरिएको छ र यो विश्वसनीय छ। यद्यपि, प्रयोगकर्तालाई त्यो अपरेशन गर्न निषेध गरिएको छ। अर्को शब्दमा, तिनीहरूसँग निर्दिष्ट विधिमा पहुँच छैन।
हाम्रा टोकनहरूसँग अलिकति छेडछाड गरौं। यदि हामीले sendMoney.sh फाइलका केही टोकनहरू परिवर्तन गर्छौं भने। हामीले यो पाउनु पर्छ:
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)
फुलस्क्रिन मोडमा प्रवेश गर्नुहोस् फुलस्क्रिन मोडबाट बाहिर निस्कनुहोस्
यो 401
अर्थ हाम्रो टोकन मान्य थिएन। यसको मतलब यो हो कि सर्भरले हाम्रो टोकन विश्वासयोग्य छ कि छैन भनेर जाँच गर्न प्रयोग गर्ने सार्वजनिक कुञ्जीले कुनै मेल फेला पारेको छैन। यदि सार्वजनिक कुञ्जीले JWT टोकनको हस्ताक्षरको मूल्याङ्कन र प्रमाणीकरण गर्न सक्दैन भने, यसले यसलाई अस्वीकार गर्नेछ।
रिक्यापको रूपमा, हेडर र "पेलोड" इन्क्रिप्ट गरिएको छैन। तिनीहरू केवल आधार 64 "इन्कोडेड" हुन्। यसको मतलब यो हो कि "डिकोडिङ" ले हामीलाई सँधै पेलोड वास्तवमा के हो भनेर हेर्नको लागि अनुमति दिन्छ। यदि हामी हाम्रो पेलोडलाई इभड्रपिङबाट जोगाउन खोजिरहेका छौं भने, हामीले टोकनको "पेलोड" प्रयोग गर्नु हुँदैन तर पहिचान प्यारामिटरहरू चयन गर्नुहोस्। समस्या वास्तवमा तब हुन्छ जब कसैले JWT
टोकनमा आफ्नो हात पाउँछ, उदाहरणका लागि, जब TLS टनेल सम्झौता गरिएको छ र कसैले आदानप्रदान गरिएका सन्देशहरूको सामग्री पढ्न सक्षम छ। जब त्यो हुन्छ, त्यहाँ अझै अर्को सुरक्षा छ। र यो हस्ताक्षर हो। सार्वजनिक कुञ्जी समावेश गर्ने सर्भरमा जाने सन्देश प्रमाणीकरण गर्न सक्षम एक मात्र हो। यो सार्वजनिक कुञ्जी, सार्वजनिक भए पनि, हस्ताक्षर र "हेडर + पेलोड" विरुद्ध दौडिएर आगमन सन्देश प्रमाणीकरण गर्न मात्र अनुमति दिन्छ।
हामी हाम्रो सत्रको अन्त्यमा पुगेका छौं। यसलाई पछ्याउनु भएकोमा धन्यवाद। हामी कसरी JWT
टोकनहरू कम्प्याक्ट छन् र तिनीहरूको XML समकक्ष, SAML
टोकनहरू भन्दा धेरै कम वर्बोस छन् भनेर देख्न सक्छौं। हामीले देख्यौं कि टोकनहरू सिर्जना गर्न र प्रयोग गर्न कति सजिलो छ निश्चित विधिहरूका लागि आवश्यक निश्चित प्राधिकरणहरू प्राप्त गर्न र हामी त्यहाँ हस्ताक्षरित टोकन मार्फत कसरी पुग्छौं। JWT
कसरी काम गर्दछ भन्ने विचार प्राप्त गर्न मलाई धेरै महत्त्वपूर्ण लाग्छ। आशा छ, यसका साथ, मैले JWT
टोकनहरूले कसरी काम गर्छ भन्ने बारेमा राम्रो परिचय दिएको छु। यी सबैले कसरी काम गर्छ भन्ने बारे राम्रो विचार प्राप्त गर्न, म तपाईंलाई लागू गरिएको cypress
परीक्षणहरूसँग खेल्न सल्लाह दिन्छु। यो कसरी अनुरोधहरू गरिन्छ र हामीले के परीक्षण गर्दैछौं र के अपेक्षा गरिएको छ भनेर हेर्नको लागि यो एक राम्रो तरिका हो। त्यसोभए तपाईले केहि प्रयोगकर्ताहरूले किन केहि अपरेशनहरू गर्न पाउँछन् र अरूले गर्दैनन् भन्ने बारे पनि राम्रो विचार प्राप्त गर्नुहुनेछ। मैले यस अनुप्रयोगको सबै स्रोत कोड GitHub मा राखेको छु। मलाई आशा छ कि तपाईंले यो लेखलाई मैले लेख्न रमाईलो गर्नु भएको छ। पढ्नु भएकोमा धन्यवाद!