Մի քանի ամիս առաջ ես ներդնում էի OpenID Connect սերվեր՝ մեր հարյուրավոր ներքին հավելվածների հասանելիությունը կառավարելու համար: Մեր սեփական զարգացումներից, ավելի փոքր մասշտաբով հարմար, մենք անցել ենք ընդհանուր ընդունված ստանդարտի: Կենտրոնական ծառայության միջոցով մուտքը մեծապես հեշտացնում է միապաղաղ գործառնությունները, նվազեցնում թույլտվությունների իրականացման ծախսերը, թույլ է տալիս գտնել բազմաթիվ պատրաստի լուծումներ և չխորացնել ձեր ուղեղը նորերը մշակելիս: Այս հոդվածում ես կխոսեմ այս անցման և այն բախումների մասին, որոնք մենք կարողացանք լրացնել:
Վաղուց... Ինչպես ամեն ինչ սկսվեց
Մի քանի տարի առաջ, երբ ձեռքով հսկողության համար չափազանց շատ ներքին հավելվածներ կային, մենք դիմում գրեցինք ընկերության ներսում հասանելիությունը վերահսկելու համար: Դա Rails-ի պարզ հավելված էր, որը միանում էր աշխատակիցների մասին տեղեկություններով տվյալների բազայի, որտեղ կարգավորվում էր տարբեր գործառույթների հասանելիությունը: Միևնույն ժամանակ, մենք բարձրացրինք առաջին SSO-ն, որը հիմնված էր հաճախորդի և լիազորման սերվերի կողմից թոքենների ստուգման վրա, նշանը գաղտնագրված ձևով փոխանցվեց մի քանի պարամետրերով և ստուգվեց լիազորման սերվերի վրա: Սա ամենահարմար տարբերակը չէր, քանի որ յուրաքանչյուր ներքին հավելված պետք է նկարագրեր տրամաբանության զգալի շերտ, և աշխատակիցների տվյալների բազաները լիովին համաժամանակացվեցին լիազորման սերվերի հետ:
Որոշ ժամանակ անց մենք որոշեցինք պարզեցնել կենտրոնացված թույլտվության խնդիրը: SSO-ն փոխանցվել է հավասարակշռողին: OpenResty-ի օգնությամբ Lua-ին ավելացվեց կաղապար, որը ստուգում էր ժետոնները, գիտեր, թե որ հավելվածն է գնում հարցումը և կարող էր ստուգել, թե արդյոք այնտեղ մուտք կա: Այս մոտեցումը զգալիորեն պարզեցրեց ներքին հավելվածների հասանելիությունը վերահսկելու խնդիրը. յուրաքանչյուր հավելվածի կոդում այլևս անհրաժեշտ չէր նկարագրել լրացուցիչ տրամաբանություն: Արդյունքում մենք փակեցինք երթևեկությունը արտաքինից, և հավելվածն ինքնին ոչինչ չգիտեր թույլտվության մասին։
Սակայն մի խնդիր չլուծված մնաց. Իսկ ի՞նչ կասեք այն հավելվածների մասին, որոնք աշխատակիցների մասին տեղեկությունների կարիք ունեն: Հնարավոր էր API գրել լիազորման ծառայության համար, բայց հետո դուք պետք է հավելյալ տրամաբանություն ավելացնեիք յուրաքանչյուր նման հավելվածի համար։ Բացի այդ, մենք ցանկանում էինք ձերբազատվել կախվածությունից մեր սեփական գրավոր հավելվածներից մեկից, որն ապագայում ուղղված է OpenSource-ի թարգմանության համար՝ մեր ներքին լիազորման սերվերից: Մենք դրա մասին կխոսենք մեկ այլ ժամանակ: Երկու խնդիրների լուծումն էլ OAuth-ն էր:
ընդհանուր չափանիշներին
OAuth-ը հասկանալի, ընդհանուր առմամբ ընդունված թույլտվության ստանդարտ է, բայց քանի որ միայն դրա ֆունկցիոնալությունը բավարար չէ, նրանք անմիջապես սկսեցին դիտարկել OpenID Connect-ը (OIDC): OIDC-ն ինքնին բաց վավերացման ստանդարտի երրորդ ներդրումն է, որը հոսել է հավելման մեջ OAuth 2.0 արձանագրության վրա (բաց թույլտվության արձանագրություն): Այս լուծումը փակում է վերջնական օգտագործողի մասին տվյալների բացակայության խնդիրը, ինչպես նաև հնարավորություն է տալիս փոխել թույլտվության մատակարարին:
Այնուամենայնիվ, մենք չընտրեցինք կոնկրետ մատակարար և որոշեցինք ավելացնել ինտեգրում OIDC-ի հետ մեր առկա թույլտվության սերվերի համար: Այս որոշման օգտին էր այն փաստը, որ OIDC-ն շատ ճկուն է վերջնական օգտագործողի թույլտվության առումով: Այսպիսով, հնարավոր եղավ իրականացնել OIDC աջակցություն ձեր ընթացիկ թույլտվության սերվերի վրա:
Մեր սեփական OIDC սերվերի ներդրման մեր եղանակը
1) Տվյալները բերեց ցանկալի ձևին
OIDC-ն ինտեգրելու համար անհրաժեշտ է ընթացիկ օգտագործողի տվյալները բերել ստանդարտով հասկանալի ձևի: OIDC-ում դա կոչվում է Հայցեր: Հայցերն ըստ էության օգտատերերի տվյալների բազայի վերջնական դաշտերն են (անուն, էլ.փոստ, հեռախոս և այլն): Գոյություն ունի
Հատկանշական նշանների խումբը համակցված է հետևյալ ենթաբազմության մեջ՝ Scope: Թույլտվության ընթացքում պահանջվում է մուտք գործել ոչ թե կոնկրետ ապրանքանիշերի, այլ շրջանակների, նույնիսկ եթե շրջանակից որոշ ապրանքանիշեր անհրաժեշտ չեն:
2) իրականացրել է անհրաժեշտ դրամաշնորհներ
OIDC-ի ինտեգրման հաջորդ մասը թույլտվության տեսակների, այսպես կոչված, դրամաշնորհների ընտրությունն ու իրականացումն է: Ընտրված հավելվածի և թույլտվության սերվերի միջև փոխգործակցության հետագա սցենարը կախված կլինի ընտրված դրամաշնորհից: Ճիշտ դրամաշնորհ ընտրելու օրինակելի սխեման ներկայացված է ստորև նկարում:
Մեր առաջին դիմումի համար մենք օգտագործեցինք ամենատարածված դրամաշնորհը՝ Լիազորման օրենսգիրքը: Նրա տարբերությունը մյուսներից այն է, որ այն եռաստիճան է, այսինքն. լրացուցիչ թեստավորում է անցնում։ Սկզբում օգտատերը կատարում է թույլտվության թույլտվության հարցում, ստանում է նշան՝ Թույլտվության կոդը, այնուհետև այս նշանով, կարծես ճանապարհորդության տոմսով, խնդրում է մուտքի նշան: Այս թույլտվության սցենարի բոլոր հիմնական փոխազդեցությունը հիմնված է հավելվածի և թույլտվության սերվերի միջև վերահղումների վրա: Դուք կարող եք կարդալ ավելին այս դրամաշնորհի մասին
OAuth-ը հավատարիմ է այն հայեցակարգին, որ թույլտվությունից հետո ձեռք բերված մուտքի նշանները պետք է լինեն ժամանակավոր և գերադասելիորեն փոխվեն միջինը 10 րոպեն մեկ: Թույլտվության օրենսգրքի դրամաշնորհը եռաստիճան ստուգում է վերահղումների միջոցով, յուրաքանչյուր 10 րոպեն մեկ նման քայլ անելը, անկեղծ ասած, ամենահաճելի գործը չէ աչքերի համար: Այս խնդիրը լուծելու համար կա ևս մեկ դրամաշնորհ՝ Refresh Token-ը, որն օգտագործել ենք նաև մեր երկրում։ Այստեղ ամեն ինչ ավելի հեշտ է։ Մեկ այլ դրամաշնորհից ստուգման ժամանակ, բացի հիմնական մուտքի նշանից, տրվում է ևս մեկը՝ Refresh Token-ը, որը կարող է օգտագործվել միայն մեկ անգամ, և դրա ժամկետը սովորաբար շատ ավելի երկար է: Այս Refresh Token-ի միջոցով, երբ հիմնական մուտքի նշանի TTL-ը (Ապրելու ժամանակը) ավարտվի, մուտքի նոր նշանի հարցումը կհասնի մեկ այլ դրամաշնորհի վերջնական կետին: Օգտագործված Refresh Token-ը անմիջապես զրոյացվում է: Այս ստուգումը երկքայլ է և կարող է իրականացվել հետին պլանում՝ օգտագործողի համար աննկատ:
3) Ստեղծեք անհատական տվյալների ելքային ձևաչափեր
Ընտրված դրամաշնորհների ներդրումից, լիազորման աշխատանքներից հետո հարկ է նշել վերջնական օգտագործողի մասին տվյալներ ստանալը։ OIDC-ն դրա համար ունի առանձին վերջնակետ, որտեղ դուք կարող եք պահանջել օգտվողի տվյալներ ձեր ընթացիկ մուտքի նշանով և եթե դրանք արդիական են: Իսկ եթե օգտատիրոջ տվյալներն այդքան հաճախ չեն փոխվում, և դուք պետք է բազմիցս հետևեք ընթացիկներին, կարող եք գալ այնպիսի լուծման, ինչպիսին են JWT տոկենները։ Այս նշանները նույնպես աջակցվում են ստանդարտով: JWT նշանն ինքնին բաղկացած է երեք մասից՝ վերնագիր (տեղեկատվություն նշանի մասին), օգտակար բեռ (ցանկացած անհրաժեշտ տվյալ) և ստորագրություն (ստորագրություն, նշանը ստորագրված է սերվերի կողմից և հետագայում կարող եք ստուգել դրա ստորագրության աղբյուրը)։
OIDC-ի իրականացման ժամանակ JWT նշանը կոչվում է id_token: Այն կարող է պահանջվել սովորական մուտքի նշանի հետ միասին, և մնում է միայն ստուգել ստորագրությունը: Լիազորման սերվերը դրա համար ունի առանձին վերջնակետ՝ ձևաչափով մի շարք հանրային բանալիներով
Օրինակ Google-ում.
{
"issuer": "https://accounts.google.com",
"authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
"token_endpoint": "https://oauth2.googleapis.com/token",
"userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
"revocation_endpoint": "https://oauth2.googleapis.com/revoke",
"jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
"response_types_supported": [
"code",
"token",
"id_token",
"code token",
"code id_token",
"token id_token",
"code token id_token",
"none"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"scopes_supported": [
"openid",
"email",
"profile"
],
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"client_secret_basic"
],
"claims_supported": [
"aud",
"email",
"email_verified",
"exp",
"family_name",
"given_name",
"iat",
"iss",
"locale",
"name",
"picture",
"sub"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:ietf:params:oauth:grant-type:jwt-bearer"
]
}
Այսպիսով, օգտագործելով id_token, դուք կարող եք փոխանցել բոլոր անհրաժեշտ նշանները նշանի օգտակար բեռին և ամեն անգամ չկապվել թույլտվության սերվերի հետ՝ օգտատիրոջ տվյալները պահանջելու համար: Այս մոտեցման թերությունն այն է, որ սերվերից օգտվողի տվյալների փոփոխությունը անմիջապես չի կատարվում, այլ մուտքի նոր նշանի հետ միասին:
Իրականացման արդյունքները
Այսպիսով, մեր սեփական OIDC սերվերի ներդրումից և հավելվածի հետ կապերը կարգավորելուց հետո մենք լուծեցինք օգտվողների մասին տեղեկատվության փոխանցման խնդիրը:
Քանի որ OIDC-ն բաց ստանդարտ է, մենք հնարավորություն ունենք ընտրելու գոյություն ունեցող մատակարար կամ սերվերի ներդրում: Մենք փորձեցինք Keycloak-ը, որը պարզվեց, որ շատ հարմար է կարգավորելու համար, հավելվածի կողմից կապի կոնֆիգուրացիան կարգավորելուց և փոխելուց հետո այն պատրաստ է գործարկման: Դիմումի կողմում մնում է միայն փոխել կապի կոնֆիգուրացիաները:
Խոսելով առկա լուծումների մասին
Մեր կազմակերպության շրջանակներում, որպես առաջին OIDC սերվեր, մենք հավաքեցինք մեր սեփական ներդրումը, որը լրացվեց ըստ անհրաժեշտության: Այլ պատրաստի լուծումների մանրամասն վերանայումից հետո կարող ենք ասել, որ դա վիճելի հարց է: Սեփական սերվերի ներդրման որոշման օգտին, պրովայդերների կողմից մտահոգություններ կային անհրաժեշտ ֆունկցիոնալության բացակայության, ինչպես նաև հին համակարգի առկայության դեպքում, որում կային տարբեր մաքսային թույլտվություններ որոշ ծառայությունների համար և բավականին շատ: աշխատակիցների մասին տվյալներն արդեն պահպանվել են: Այնուամենայնիվ, պատրաստի իրագործումներում կան ինտեգրման հարմարություններ։ Օրինակ, Keycloak-ն ունի օգտատերերի կառավարման իր համակարգ, և տվյալները պահվում են անմիջապես դրա մեջ, և դժվար չի լինի այնտեղ առաջ անցնել ձեր օգտատերերից։ Դրա համար Keycloak-ն ունի API, որը թույլ կտա ամբողջությամբ իրականացնել փոխանցման բոլոր անհրաժեշտ գործողությունները:
Վկայագրված, հետաքրքիր, իմ կարծիքով, իրականացման մեկ այլ օրինակ Ory Hydra-ն է: Հետաքրքիր է, քանի որ այն բաղկացած է տարբեր բաղադրիչներից։ Ինտեգրվելու համար դուք պետք է կապեք ձեր օգտատերերի կառավարման ծառայությունը նրանց լիազորման ծառայությանը և անհրաժեշտության դեպքում ընդլայնեք:
Keycloak-ը և Ory Hydra-ն միակ լուծումները չեն, որոնք վաճառվում են: Ավելի լավ է ընտրել OpenID հիմնադրամի կողմից վավերացված իրականացում: Այս լուծումները սովորաբար ունեն OpenID հավաստագրման նշան:
Մի մոռացեք նաև առկա վճարովի մատակարարների մասին, եթե չեք ցանկանում պահպանել ձեր OIDC սերվերը: Այսօր շատ լավ տարբերակներ կան։
Ինչ է հաջորդը
Մոտ ապագայում մենք պատրաստվում ենք այլ կերպ փակել տրաֆիկը դեպի ներքին ծառայություններ։ Մենք նախատեսում ենք փոխանցել մեր ընթացիկ SSO-ն հաշվեկշռի վրա՝ օգտագործելով OpenResty-ը OAuth-ի վրա հիմնված վստահված անձի: Այստեղ արդեն շատ պատրաստի լուծումներ կան, օրինակ.
Լրացուցիչ նյութեր
Source: www.habr.com