JAX-RS və Jersey ilə REST-ə əsaslanan identifikasiya üçün ən yaxşı təcrübələr

Cersidə identifikasiya işarələrini təmin etmək üçün bir yol axtarıram. Hər hansı bir çərçivəni istifadə etməməyə çalışıram. Mümkündürmü?

Mənim planım: istifadəçi veb xidmətimə abunə, mənim web xidmətim bir simli yaradır, müştəriyə göndərir və müştəri onu saxlayır. Müştəri daha sonra istifadəçi adı və şifrə əvəzinə hər bir istək üçün bir mö'cüzə göndərir.

Mən hər sorgu və @PreAuthorize("hasRole('ROLE')") üçün xüsusi bir filtre istifadə @PreAuthorize("hasRole('ROLE')") düşündüm @PreAuthorize("hasRole('ROLE')") amma yalnız bir çox verilənlər bazası sorgusunun, @PreAuthorize("hasRole('ROLE')") həqiqətən olub olmadığını kontrol etməsinə səbəb olduğunu düşündüm.

Və ya filtr yaratmırsınız və hər bir tələbdə param marker qoyursunuz? Beləliklə, hər bir API əvvəlcə simvolu yoxlayır və sonra resursu almaq üçün bir şey icra edir.

356
06 нояб. DevOps85 06 Noyabrda təyin olundu. 2014-11-06 13:26 '14 saat 13:26 'da 2014-11-06 13:26
@ 2 cavablar

Nasaf autentifikasiyası necə işləyir?

Cetvele kimlik doğrulaması yaparken, müşteri, bir simge deyilən bir veri parçası üçün sert kimlik bilgilerini (məsələn, istifadəçi adı və şifre) birbirine çevirir. Hər bir tələb üçün, ağır etimadnamələri göndərmək əvəzinə, müştəri identifikasiyası və icazə vermək üçün serverə bir mö'cüzə göndərir.

Bir neçə sözlə, bir mö'cüzə əsaslı autentifikasiya sxemi aşağıdakı addımları yerinə yetirir:

  1. Müştəri öz etimadnaməsini (istifadəçi adı və şifrəni) serverə göndərir.
  2. Server etimadnaməsini təsdiqləyir və əgər etibarsızsa, istifadəçi üçün bir göstərici yaradır.
  3. Server, istifadəçi kimliyi və son istifadə tarixi ilə birlikdə, əvvəllər hazırlanmış bir məxfi saxlayır.
  4. Server, əmtəə nişanını müştəriyə göndərir.
  5. Müştəri hər sorğuda serverə bir mö'cüzə göndərir.
  6. Hər bir istəkdə olan server gələn istəkdən token alır. Bir simge istifadə edərək, server identifikasiyası üçün istifadəçi məlumatlarını tarar.
    • Token etibarlıysa, server tələbi qəbul edir.
    • Siqnalı etibarsız vəziyyətdə, server tələbi rədd edir.
  7. Kimlik doğrulamasından sonra, server icazə verir.
  8. Server göstəriciləri yeniləmək üçün bir son nöqtə təmin edə bilər.

Qeyd Əgər server imzalanmış bir token (məsələn, saxlanmadan autentifikasiya etməyə imkan verən JWT) çıxarsa, 3 addım tələb olunmur.

JAX-RS 2.0 (Jersey, RESTEasy və Apache CXF) ilə nə edə bilərsiniz?

Bu həll yalnız bir JAX-RS 2.0 API istifadə edir, müəyyən bir təchizatçı üçün hər hansı bir həlldən qaçınır. Beləliklə, Cersi , RESTEasyApache CXF kimi JAX-RS 2.0 tətbiqləri ilə işləməlidir .

Token əsaslı autentifikasiya istifadə etsəniz, servlet konteynerinin təqdim etdiyi standart Java EE veb tətbiqi təhlükəsizlik mexanizmlərinə web.xmlweb.xml proqramları vasitəsilə konfiqurasiya web.xml . Bu əsas identifikasiyasıdır.

İstifadəçi adı və şifrəsi və simvolu verilməsi ilə istifadəçi identifikasiyası

Kimlik məlumatlarını (istifadəçi adı və şifrəni) alan və təsdiq edən bir JAX-RS qaynaq metodu yaradın və istifadəçi üçün simvol verir:

 username=admin> 

Forma parametrləri yerinə bir istifadəçi adı və şifrəni bir siniflə əlaqələndirə bilərsiniz:

 @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response authenticateUser(Credentials credentials) { String username = credentials.getUsername(); String password = credentials.getPassword(); // Authenticate the user, issue a token and return a response } 

Bu yanaşmanı istifadə edərək, müştəri sorğu yükləməsində aşağıdakı formada etimadnaməsini göndərməlidir:

 Authorization: Bearer <token-goes-here> 

Standart HTTP başlığı adı müvəqqəti deyil, çünki təsdiqləmə məlumatı deyil, avtorizasiya deyil. Lakin, bu, serverə etimadnaməsini göndərmək üçün standart HTTP başlıqlıdır.

JAX-RS bir @NameBinding təmin edir, meta-annotasiya filtreler və interceptors resurs dərsləri və üsulları ilə bağlı digər annotasiya yaratmaq üçün istifadə olunur. @Secured şərhləri aşağıdakı kimi müəyyənləşdirin:

ContainerRequestFilter tətbiq edən filter sinifini bəzəmək üçün istifadə olunacaq və bu, resurs metodu ilə işlənməməzdən əvvəl istəniləni tutmağa imkan verir.  HTTP sorğu başlıqlarına daxil olmaq və sonra mö'cüzə almaq üçün ContainerRequestContext istifadə edə bilərsiniz: 

 @Path("/example") public class ExampleResource { @GET @Path("{id}") @Produces(MediaType.APPLICATION_JSON) public Response myUnsecuredMethod(@PathParam("id") Long id) { // This method is not annotated with @Secured // The authentication filter won't be executed before invoking this method ... } @DELETE @Secured @Path("{id}") @Produces(MediaType.APPLICATION_JSON) public Response mySecuredMethod(@PathParam("id") Long id) { // This method is annotated with @Secured // The authentication filter will be executed before invoking this method // The HTTP request must be performed with a valid token ... } } 

Yuxarıdakı nümunədə filter yalnız mySecuredMethod(Long) üçün icra ediləcək, çünki bu, @Secured ilə @Secured .

Cari istifadəçi identifikasiyası

Yenə REST API üçün tələbi yerinə yetirən istifadəçi ilə tanış olmaq lazımdır. Buna nail olmaq üçün aşağıdakı yanaşmaları istifadə edə bilərsiniz:

Cari sorğunun təhlükəsizliyini ləğv edin

Mövcud istək üçün ContainerRequestFilter.filter(ContainerRequestContext) metodunda, SecurityContext yeni bir nümunəsi təyin edilə bilər. Sonra Principal nümunəsini qaytarmaq üçün SecurityContext.getUserPrincipal()

SecurityContext tətbiq: 

 @GET @Secured @Path("{id}") @Produces(MediaType.APPLICATION_JSON) public Response myMethod(@PathParam("id") Long id, @Context SecurityContext securityContext) { ... } 

Və sonra Principal almaq:

SecurityContext yazmaq istəmirsinizsə, hadisələr və istehsalçılar kimi faydalı xüsusiyyətləri təmin edən CDI (Bağlam və Bağımlılık Enjeksiyonu) istifadə edə bilərsiniz. 

Bir CDI seçicisi yaradın:

 @Inject @AuthenticatedUser Event<String> userAuthenticatedEvent; 

Kimlik doğrulaması müvəffəq olsa, istifadəçi adını parametr kimi keçirən bir hadisə tetikleyin (yadda saxlayın ki, simge istifadəçiyə verilir və istifadəçi identifikatorunu tapmaq üçün istifadə olunur):

 @RequestScoped public class AuthenticatedUserProducer { @Produces @RequestScoped @AuthenticatedUser private User authenticatedUser; public void handleAuthenticationEvent(@Observes @AuthenticatedUser String username) { this.authenticatedUser = findUser(username); } private User findUser(String username) { // Hit the the database or a service to find a user by its username and return it // Return the User instance } } 

Doğrulanmış İstifadəçi sahəsi, JAX-RS xidmətləri, CDI komponentləri, servlets və EJBs kimi konteyner idarəedici komponentlərə daxil edilə bilən User nümunəsini yaradır. Bir User instansiyasına daxil olmaq üçün aşağıdakı kod parçasını istifadə edin (əslində bu bir CDI proxy):

@Produces annotasiya JAX-RS-dən fərqlidir: 

AuthenticatedUserProducer komponentində CDI @Produces annotasiyasını istifadə etdiyinizə əmin olun.

Burada əsas nöqtə @RequestScoped ilə @RequestScoped bir fasulyəsdir və siz filtrlər və lobya arasında məlumat mübadiləsi @RequestScoped . Hadisələrdən istifadə etmək istəmirsinizsə, sorğu açıldıqdan sonra təsdiqlənmiş istifadəçi komponentinə saxlamağın filtresini dəyişə və sonra onu JAX-RS resurs siniflərindən oxuya bilərsiniz.

SecurityContext ləğv etdiyi yanaşma ilə müqayisədə, CDI yanaşması JAX-RS provayderlərindən və resurslarından başqa komponentlərdən təsdiqlənmiş bir istifadəçi əldə etməyə imkan verir.

Rolu Avtorizasiya Dəstəyi

Rolu əsaslı icazə verməyin dəstəklənməsi haqqında daha ətraflı məlumat üçün, digər cavaba baxın .

Siqnalların verilməsi

Token ola bilər:

  • Opaq: dəyərin özü (məsələn, təsadüfi bir simli)
  • Offline: markanın özü haqqında məlumatları ehtiva edir (məsələn, JWT).

Aşağıdakı detallara baxın:

Random simli kimi simli

Təsadüfi bir simli yaratmaq və verilənlər bazasında istifadəçi identifikasiyası və son istifadə tarixi ilə birlikdə saxlayaraq bir token verilə bilər. Burada təsadüfi bir simli Java yaratmaq üçün yaxşı bir nümunə burada görülə bilər. Siz də istifadə edə bilərsiniz:

RFC 7519 tərəfindən müəyyən edilir. 

Bu, iddialarda ətraflı məlumatların saxlanmasına imkan verən müstəqil bir mö'cüzədir. Bu iddialar, Base64 kimi kodlanan JSON olan mö'cüzənin yüklənməsində saxlanılır. RFC 7519-da qeydiyyatdan keçmiş bəzi tətbiqlər və onlar deməkdir (daha ətraflı məlumat üçün tam RFC-i oxuyun):

  • iss : Token verən müdir.
  • sub : JWT mövzusu olan Principal.
  • exp : token bitmə tarixi.
  • nbf : token işlənməyə qəbul ediləcək zaman.
  • iat : iat vaxt.
  • jti : simge üçün unikal identifikator.

Bir parol ilə parol kimi həssas məlumatları saxlamamağınızı unutmayın.

Fayda yükü müştəri tərəfindən oxunur və mö'cüzənin bütövlüyü serverdəki imzanı doğrulayaraq asanlıqla təsdiqlənə bilər. İmza saxta saxtakarlıqa mane olan şeydir.

Siz onları izləmək lazım deyilsə JWT simvollarını saxlamağa ehtiyacınız olmayacaq. Cetvele baxmayaraq, siz onları ləğv etmək və ləğv etmək imkanı əldə edəcəksiniz. JWT simvollarının izlərini saxlamaq üçün serverdə bütün mö'cüzəni saxlamağa əvəzinə, simge identifikatorunu ( jti tələbi) digər məlumatlarla birlikdə, məsələn, nişan verdiyiniz istifadəçi, sona çatma tarixi və s. Kimi saxlaya bilərsiniz.

Ayələr saxlayarkən, həmişə köhnə məlumatları silmək məsləhət görülür, belə ki, verilənlər bazası müddəti uzadılmayacaq.

JWT istifadə

JWT simvollarının verilməsi və təsdiqlənməsi üçün bir neçə Java kitabxanası var:

JWT ilə işləmək üçün digər faydalı resursları tapmaq üçün http://jwt.io ünvanına baxın .

JWT istifadə edərək bir mö'cüzə yeniləməsini idarə etmək

Yeniləmə üçün yalnız etibarlı (vaxtı keçməmiş) simvolları qəbul edin. Müştərinin exp üçün ərizədə göstərilən sona çatma tarixindən əvvəl ayələrini yeniləmək üçün məsuliyyəti.

Sənədləri qeyri-müəyyən olaraq yenilənməməlisiniz. Aşağıda hesab edə biləcəyiniz bir neçə yanaşma tapa bilərsiniz.

Sembolunuza iki iddia əlavə edərkən token yeniləmə izini saxlaya bilərsiniz (iddiaların adları sizə bağlıdır):

  • refreshLimit : refreshLimit neçə dəfə yenilənə biləcəyini göstərir.
  • refreshCount : göstəricinin neçə dəfə yeniləndiğini göstərir.

Aşağıdakı şərtlər doğru olduqda sadəcə yeniləməni yeniləyin:

  • Token ( exp >= now ) başa exp >= now .
  • refreshCount < refreshLimit refresh refreshCount < refreshLimit sayı yeniləmə mümkündür ( refreshCount < refreshLimit ).

Bir simgeyi yenilədiğinde:

  • Son istifadə tarixini ( exp = now + some-amount-of-time ) yeniləyin.
  • refreshCount++ token yeniləmə ( refreshCount++ ).

Alternativ olaraq, içkinin sayını izləmək üçün mütləq son istifadə tarixini (yuxarıda təsvir olunan refreshLimit bənzər) göstərən bir refreshLimit ehtiyac ola bilər. Mütləq sona çatma tarixinə qədər hər hansı bir miqdarda sərinləşdirici içkilər qəbul edilə bilər.

Digər bir yanaşma, qısamüddətli JWT simvollarını təqdim etmək üçün istifadə olunan ayrı bir uzun müddətli yeniləmə möcüzəsinin verilməsi ilə bağlıdır.

Ən yaxşı yanaşma tələblərinizdən asılıdır.

JWT ilə Token ləğv edilməsi

Siqaretləri ləğv etmək istəyirsinizsə, onları təqib etməlisiniz. Sunucunun bütün simgesini saxlamanıza ehtiyac yoxdur, yalnız markerin identifikatorunu (unikal olmalıdır) və bəzi metadata saxlamaq lazımdır. Etiket identifikatoru üçün bir UUID istifadə edə bilərsiniz.

jti tələbi token identifikatorunu jti saxlamaq üçün istifadə olunmalıdır. jti , jti tələbinin dəyərini server tərəfində olan jti identifikatorlarına qarşı jti ləğv edilməmiş olduğundan əmin olun.

Təhlükəsizliyə görə, parol dəyişdikdə bir istifadəçi üçün bütün mö'cüzələri ləğv edin.

Əlavə məlumat

  • Istifadə etmək qərarına gəldiyiniz hansı identifikasiya növü əhəmiyyətli deyil. Həmişə bir insan-in-the-orta hücum qarşısını almaq üçün bu bir HTTPS bağlantısı üst etmək.
  • Siqnallar haqqında daha ətraflı məlumat üçün İnformasiya Təhlükəsizliyi bu suallara baxın.
  • Bu yazıda kimlik doğrulama belirteçleri haqqında faydalı informasiya tapa bilərsiniz.
1142
06 нояб. Cassio Mazzochi Molin tərəfindən verilmiş cavab 06 noyabr 2014-11-06 14:17 '14 at 14:17 2014-11-06 14:17

Bu cavab avtorizasiya haqqındadir və bu, mənim əvvəlki identifikasiya cavabına bir əlavədir .

Niyə başqa bir cavab lazımdır? JSR-250 ek notlarına necə dəstək verilməsi barədə ətraflı məlumat əlavə edərək əvvəlki cavabımı uzatmağa çalışdım. Lakin, orijinal cavab çox uzun oldu və maksimum 30,000 simvolu aşdı. Buna görə də, bütün icazə məlumatlarını bu cavana köçürdüm, başqa bir cavab isə autentifikasiya və sənədlər verməyə yönəlmişdi.


@Secured annotasiya ilə rolu əsasında avtorizasiya dəstəyi

Başqa bir cavabda göstərilən identifikasiya akışına əlavə olaraq , rolu əsasında icazə REST son nöqtələrində dəstəklənə bilər.

Nömrəni yaradın və sizin ehtiyaclarınıza uyğun olaraq rolları müəyyən edin:

 @NameBinding @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Secured { Role[] value() default {}; } 

Daha sonra, @Secured yerinə yetirmək üçün @Secured təmin edən resurs dərsləri və metodlarını şərh edin. Metodun əlavə notları sinif notlarını ləğv edir:

AUTHENTICATION prioritet AUTHENTICATION sonra işləyən AUTHORIZATION prioritetli filtr yaradın. 

ResourceInfo sorğu işləyəcək MethodClass resurslarını əldə etmək üçün istifadə edilə bilər və sonra @Secured əlavələri @Secured :

border=0
SecurityContext (который должен быть уже установлен в ContainerRequestContext ) или использовать его с помощью CDI, в зависимости от подхода, для которого вы идете. 

Если аннотация @Secured не имеет объявленных ролей, вы можете предположить, что все @Secured аутентификацию пользователи могут получить доступ к этой конечной точке, не обращая внимания на роли, которые есть у пользователей.

Поддержка ролевой авторизации с аннотациями JSR-250

В качестве альтернативы для определения ролей в аннотации @Secured как показано выше, вы можете рассмотреть аннотации JSR-250, такие как @RolesAllowed , @PermitAll и @DenyAll .

JAX-RS не поддерживает такие аннотации из коробки, но это может быть достигнуто с помощью фильтра. Вот несколько соображений, которые следует учитывать, если вы хотите поддержать их всех:

Таким образом, фильтр авторизации, который проверяет аннотации JSR-250, может быть таким:

RolesAllowedDynamicFeature . Если вы используете Джерси, вам не нужно писать собственный фильтр, просто используйте существующую реализацию. 

57
ответ дан Cassio Mazzochi Molin 22 авг. '17 в 12:44 2017-08-22 12:44

Другие вопросы по меткам или Задайте вопрос