Feathers: рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЕрдЧрд▓рд╛

рдХреЛ рдирд┐рд░реНрдорд┐рдд 6 рдЕрдХреНрддреВре░ 2018  ┬╖  10рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: feathersjs/feathers

рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдлреЗрджрд░реНрд╕ рдХреНрд░реЛ рд░реЛрдбрдореИрдк рдЕрдкрдбреЗрдЯ рдореЗрдВ рдереЛрдбрд╝рд╛ рдкрд╣рд▓реЗ рд╣реА рд▓рд┐рдЦрд╛ рдерд╛ред рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдЙрди рд╕рднреА рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ рдХреЛ рдПрдХрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ, рдЬрд┐рдиреНрд╣реЗрдВ рдкрдВрдЦ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреЗ рдЕрдЧрд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдврд╛рдВрдЪрд╛ рд╕реНрд╡рддрдВрддреНрд░

рд╡рд░реНрддрдорд╛рди (рдмрдЬрд╝рд░реНрдб) рд░рд┐рд▓реАрдЬ рдХреЗ рд╕рд╛рде, рдкрдВрдЦ рдХреЛрд░ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рд╣реЛ рдЧрдпрд╛, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдкреНрд▓рдЧрдЗрди рдЕрднреА рднреА рдХреБрдЫ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдкрдВрдЬреАрдХреГрдд рдХрд░ рд░рд╣рд╛ рд╣реИред рдЕрдЧрд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рд╡рд╣ рдорд┐рдбрд▓рд╡реЗрдпрд░ @рдлреЗрджрд░рдЬрдЬ/рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдореЗрдВ рдЪрд▓рд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреЛрд░ рдХреЛ рднреА рдврд╛рдВрдЪрд╛ рд╕реНрд╡рддрдВрддреНрд░ рдмрдирд╛ рджреЗрдЧрд╛ред рдпрд╣ рдХреЛрдЖ рдпрд╛ рдПрдордХреНрдпреВрдЯреАрдЯреА рдЬреИрд╕реЗ рдирдП рдкрд░рд┐рд╡рд╣рди рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред

рдмреЗрд╣рддрд░ рд╕реЙрдХреЗрдЯ рдкреНрд░рдорд╛рдгреАрдХрд░рдг

рд╡рд░реНрддрдорд╛рди рдореЗрдВ, websockets рдХреЛ рдкреНрд░рдорд╛рдгрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдХрд╕реНрдЯрдо рдИрд╡реЗрдВрдЯ рддрдВрддреНрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд▓реЙрдЧ рдЖрдЙрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдХреБрдЫ рдореБрджреНрджреЛрдВ рдХрд╛ рдХрд╛рд░рдг рдмрди рд░рд╣рд╛ рдерд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдХрднреА-рдХрднреА "рдиреЛ рдСрде рдЯреЛрдХрди" рддреНрд░реБрдЯрд┐рдпрд╛рдВ), рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рджреЛрдиреЛрдВ рдкрдХреНрд╖реЛрдВ, рд╕рд░реНрд╡рд░ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдкрд░ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рдкреБрди: рдХрдиреЗрдХреНрд╢рди рдХреЗ рдЖрд╕рдкрд╛рд╕ред

рдмреЗрд╣рддрд░ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреНрд▓рд╛рдЗрдВрдЯ

рдпрд╣ рд╕реНрдЯреЗрдЯрдлреБрд▓ рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди рдкрд░ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рд╣рдЯрд╛ рджреЗрдЧрд╛ рдФрд░ рд╕реЙрдХреЗрдЯ рд░реА-рдСрдереЗрдВрдЯрд┐рдХреЗрд╢рди рдХреЛ рдЗрдирд╛рдпрдд рд╕реЗ рд╣реИрдВрдбрд▓ рдХрд░реЗрдЧрд╛ред

рдХреЛрдИ рдФрд░ рдХреБрдХреА рдирд╣реАрдВ, рдмреЗрд╣рддрд░ oAuth

рдкрдВрдЦ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдЬреЗрдбрдмреНрд▓реНрдпреВрдЯреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдкреАрдЖрдИ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдЬрд╣рд╛рдВ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдкрдВрдЦ рд╕реЗрдЯрдЕрдк рдХреБрдХреАрдЬрд╝ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдПрдХ oAuth (Facebook, Google рдЖрджрд┐) рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдкреНрд░рд╡рд╛рд╣ рдХреЗ рдмрд╛рдж рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЛ JWT рдкрд╛рд╕ рдХрд░рдирд╛ рд╣реИред рдирдпрд╛ oAuth рдФрд░ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреНрд▓рд╛рдЗрдВрдЯ рдЕрдм рдХреБрдХреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ рдФрд░ oAuth рдкреНрд░рд╡рд╛рд╣ рдХреЛ рдПрдХ рд╕рд╛рде рд╕рдм рдХреБрдЫ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рджреЛ рднрд╛рдЧреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдЧрд╛ред рдУрдПрде рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди рдПрдХ рдХреНрд░реЙрд╕-рдбреЛрдореЗрди рдлреНрд░реЗрдВрдбрд▓реА (рдХреЗрд╡рд▓ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рд╕реБрд▓рдн) рдпреВрдЖрд░рдПрд▓ рд╣реИрд╢ рдореЗрдВ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрд┐рд╕реЗ рдлреЗрджрд░ рдорд╛рдирдХ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рддрдВрддреНрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЬреЗрдбрдмреНрд▓реНрдпреВрдЯреА рдХреЗ рд▓рд┐рдП рдПрдХреНрд╕рдЪреЗрдВрдЬ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдмреЗрд╣рддрд░ рд╡рд┐рдХрд▓реНрдк рд╣реИрдВрдбрд▓рд┐рдВрдЧ

рд╕рднреА рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдЕрдм рд░рдирдЯрд╛рдЗрдо рдкрд░ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЗрд╕рд▓рд┐рдП рдЙрдиреНрд╣реЗрдВ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рд╕реЗрдЯ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ рдФрд░ рдЙрди рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд╣реЛрдЧреА рдЬрд┐рдирдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдпрд╣ рдПрдХ рдХрд╕реНрдЯрдо рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕реЗрд╡рд╛ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреА рднреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред

рдЯреЛрдХрди рд░реАрдлрд╝реНрд░реЗрд╢ рдХрд░реЗрдВ рдФрд░ рдХрд╛рд▓реА рд╕реВрдЪреА рдореЗрдВ рдбрд╛рд▓реЗрдВ

рдореМрдЬреВрджрд╛ рдЬреЗрдбрдмреНрд▓реНрдпреВрдЯреА рдХреЗ рд╕рд╛рде рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдиреЗ рдХреЗ рдмрдЬрд╛рдп рдорд╛рдирдХ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕реЗрд╡рд╛ рдЕрдм рд▓рдВрдмреЗ рд╕рдордп рддрдХ рд░реАрдлреНрд░реЗрд╢ рдЯреЛрдХрди рднреА рд▓реМрдЯрд╛рдПрдЧреАред рдЯреЛрдХрди рдмреНрд▓реИрдХрд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдХреЛ рдЕрднреА рднреА рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рд▓реЗрдХрд┐рди рдирдИ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕реЗрд╡рд╛ рдореЗрдВ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХреАрдХреГрдд рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реЛрдЧрд╛ред

Authentication Breaking Change

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдЖрдк рдорд╛рд╕реНрдЯрд░ рд╢рд╛рдЦрд╛ рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдкреНрд░рдЧрддрд┐ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЬрдм рдмреАрдЯрд╛ рдЯреЗрд╕реНрдЯрд░ рдЗрд╕реЗ рдЖрдЬрдорд╛ рд╕рдХрддреЗ рд╣реИрдВ рддреЛ рдореИрдВ рдПрдХ рдмреНрд▓реЙрдЧ рдкреЛрд╕реНрдЯ рдбрд╛рд▓реВрдВрдЧрд╛ред рд╕реНрдерд┐рддрд┐ рд╣реИ:

| рдореЙрдбреНрдпреВрд▓ | рдХреЛрдб | рдбреЙрдХреНрд╕ | рд╕реАрдПрд▓рдЖрдИ
| --- |:---:|:---:|---:|
| @Federsjs/рдкреНрд░рдорд╛рдгреАрдХрд░рдг | | 100% | |
| @Federsjs/рдкреНрд░рдорд╛рдгреАрдХрд░рдг-рд╕реНрдерд╛рдиреАрдп | | 80% | |
| @рдлреЗрджрд░рдЬрд╕/рдкреНрд░рдорд╛рдгреАрдХрд░рдг-рд╢рдкрде | | 90%| |
| @рдлреЗрджрд░рдЬрд╕/рдкреНрд░рдорд╛рдгреАрдХрд░рдг-рдХреНрд▓рд╛рдЗрдВрдЯ | | 80%| |

рд╕рднреА 10 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдкрд╛рд╕рдкреЛрд░реНрдЯ рдмрд╣рд┐рд╖реНрдХреГрдд рдХрд░реЗрдВ

рдпрд╣ рдЪрд░реНрдЪрд╛ #844 рдореЗрдВ рд╢реБрд░реВ рд╣реБрдИ рдФрд░ https://github.com/phersjs/phers/issues/844#issuecomment -390123148 тАЛтАЛрдореЗрдВ рдЙрди рдмрд┐рдВрджреБрдУрдВ рдХрд╛ рд╕рд╛рд░рд╛рдВрд╢ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдРрд╕рд╛ рдХреНрдпреЛрдВ рд╣реЛ рд░рд╣рд╛ рд╣реИред рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдкрд╛рд╕рдкреЛрд░реНрдЯрдЬреЗрдПрд╕ рдореЗрдВ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдЕрдиреНрдп рд╕рд╣рд╛рдпрдХ рдврд╛рдВрдЪреЗ рдХреЗ рдЖрд╕рдкрд╛рд╕ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╡рд┐рдХрд╛рд╕ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ рдФрд░ рдХреЛрдЖ рдпрд╛ рд╣рд╛рдкреА рдЬреИрд╕реЗ рдЕрдзрд┐рдХрд╛рдВрд╢ рдЕрдиреНрдп HTTP рдврд╛рдВрдЪреЗ рдЕрдзрд┐рдХ рд▓рдЪреАрд▓реЗ рдФрд░ рдиреНрдпреВрдирддрдо рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ (рдЬреИрд╕реЗ https://github.com/simov/grant) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝реЗ рд╣реИрдВред рдУрдПрде рдХреЗ рд▓рд┐рдП)ред рдпрд╣ рднреА рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ рдХреЗрд╡рд▓ рдЪрд╛рд░ рдкреНрд░рдХрд╛рд░ рдХреА рд░рдгрдиреАрддрд┐рдпрд╛рдБ рд╣реИрдВ рдЬрд┐рдирдХреА рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

  • рд╕реНрдерд╛рдиреАрдп (рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо/рдкрд╛рд╕рд╡рд░реНрдб)
  • рдЬреЗрдбрдмреНрд▓реНрдпреВрдЯреА
  • oAuth (+ oAuth рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди)
  • рдПрдкреАрдЖрдИ рдХреБрдВрдЬреА

рдкрд╛рд╕рдкреЛрд░реНрдЯ рдХреЗ рдЖрд╕рдкрд╛рд╕ рдХрд╛рдо рдХрд┐рдП рдмрд┐рдирд╛, рдкрдВрдЦ рдЖрд╕рд╛рдиреА рд╕реЗ рдХрд┐рд╕реА рднреА HTTP рдкреБрд╕реНрддрдХрд╛рд▓рдп рдФрд░ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдкрд░рд┐рд╡рд╣рди рддрдВрддреНрд░ (рдЬреИрд╕реЗ рдПрдордХреНрдпреВрдЯреАрдЯреА рдпрд╛ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдХрд┐ рдкреА 2 рдкреА рдХрдиреЗрдХреНрд╢рди) рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рдмреИрда рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рддрдВрддреНрд░ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рд╕рдордЭрдиреЗ рдФрд░ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИред

params.authentication рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛

рдкрдВрдЦ рдХреА рддрд░рдл, рд╕реЗрд╡рд╛ рдХреЙрд▓ рдореЗрдВ params.authentication рд╕реЗрдЯ рдХрд░рдирд╛ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХрд╛ _only_ рддрд░реАрдХрд╛ рд╣реЛрдЧрд╛ред params.authentication рдореЗрдВ рд╕рд░реНрд╡рд┐рд╕ рдХреЙрд▓ рдХреЛ рдкреНрд░рдорд╛рдгрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрдЧреА рдФрд░ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП { strategy: 'local', email: 'email', password: 'password' } рдХреЗ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рд╣реЛрдЧреА рдЬрд┐рд╕рдХрд╛ рдкрд╣рд▓реЗ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ:

// Call `find` with a given JWT
app.service('messages').find({
  authentication: {
    strategy: 'jwt',
    accessToken: 'someJWT'
  }
});

рдХреЙрд▓рд░ (рдЬреИрд╕реЗ REST рдпрд╛ рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ, рд╣реБрдХ рдпрд╛ рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ) params.authentication рдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧрд╛ред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдЕрдм рдХреЛрдИ рднреНрд░рдо рдирд╣реАрдВ рд╣реЛрдЧрд╛ рдЕрдЧрд░ authenticate рд╣реБрдХ рдЖрдВрддрд░рд┐рдХ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рдЪрд▓рддрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВ рдпрд╛ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЬрд╛рдирдХрд╛рд░реА рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрд╣рд╛рдВ рд╕реЗ рдЖ рд░рд╣реА рд╣реИред

authenticate рд╣реБрдХ

authenticate рд╣реБрдХ рдореМрдЬреВрдж рд░рд╣реЗрдЧрд╛ред рдпрд╣ рд░рдгрдиреАрддрд┐ рдХреЗ рдирд╛рдореЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд▓реЗрдЧрд╛ рдФрд░ рдпрд╛ рддреЛ

  • рдкрд╣рд▓реА рд░рдгрдиреАрддрд┐ рдХреЗ рд╕рд╛рде рдЕрдЧрд▓реЗ рд╣реБрдХ рдкрд░ рдЬрд╛рд░реА рд░рдЦреЗрдВ рдЬрд┐рд╕рдиреЗ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рдлреЗрдВрдХреА рдФрд░ рдЗрд╕рдХреЗ рд╡рд╛рдкрд╕реА рдореВрд▓реНрдп (рдиреАрдЪреЗ рджреЗрдЦреЗрдВ) рдХреЛ params рдорд░реНрдЬ рдХрд░реЗрдВ
  • рдпрд╛ рд╕рднреА рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреЗ рд╡рд┐рдлрд▓ рд╣реЛрдиреЗ рдкрд░ рд╡рд┐рдлрд▓ рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдкрд╣рд▓реА рд░рдгрдиреАрддрд┐ рдХреА рддреНрд░реБрдЯрд┐ рдХреЛ рдлреЗрдВрдХ рджреЗрдВ

    рдпрджрд┐ params.authentication рдореЗрдВ strategy рдирд╛рдо рд╢рд╛рдорд┐рд▓ рд╣реИ рддреЛ рдХреЗрд╡рд▓ рдЙрд╕ рд░рдгрдиреАрддрд┐ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЕрдиреНрдпрдерд╛ рд╕рднреА рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ params.authentication рдмрд┐рд▓реНрдХреБрд▓ рднреА рд╕реЗрдЯ рдирд╣реАрдВ рд╣реИ, рддреЛ рд╣реБрдХ рд╣реЛрдЧрд╛

  • рдмрд╛рд╣рд░реА рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рдПрдХ рддреНрд░реБрдЯрд┐ рдлреЗрдВрдХреЛ

  • рдЖрдВрддрд░рд┐рдХ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣ рдЬрд╛рд░реА рд░рдЦреЗрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ params.user рд╕реЗрдЯ рдХрд░рддреЗ рд╕рдордп)
app.service('messages').hooks({
  before: authenticate('jwt', 'local', 'anonymous')
});

рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд░рдгрдиреАрддрд┐рдпрд╛рдБ

рдПрдХ рдмреБрдирд┐рдпрд╛рджреА рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд░рдгрдиреАрддрд┐ рдПрдХ рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд╕реНрддреБ рд╣реИ authenticate рд╡рд┐рдзрд┐ рдХрд╛ рдбреЗрдЯрд╛ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ params.authentication рдФрд░ рдПрдХ рд╕рдлрд▓рддрд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдпрд╛ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдлреЗрдВрдХрддрд╛ рд╣реИ рддреЛ рдпрд╣ рд╕рдлрд▓ рдирд╣реАрдВ рдерд╛:

const { Forbidden } = require('@feathersjs/errors');

const daveStrategy = {
  async authenticate (authParams) {
    const { username, password } = authParams;

    if (username === 'david' && password === 'secret') {
      return {
        user: {
          name: 'Dave',
          admin: true
        }
      };
    }

    throw new Forbidden('Not super Dave');
  }
};

app.authentication.registerStrategy('superdave', daveStrategy);

authenticate рд╣реБрдХ рдореЗрдВ, рд▓реМрдЯрд╛рдИ рдЧрдИ рд╡рд╕реНрддреБ рдХреЛ рд╕реЗрд╡рд╛ рдХреЙрд▓ params рдореЗрдВ рд╡рд┐рд▓рдп рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдЙрджрд╛рд╣рд░рдг params.user рд╕реЗрдЯ рдХрд░реЗрдЧрд╛ред

рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░

рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд░рдгрдиреАрддрд┐рдпреЛрдВ рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ рдЕрддрд┐рд░рд┐рдХреНрдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд╢рд╛рдорд┐рд▓ рдФрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдкрдВрдЦ рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреЛ рдЙрди рд╡рд░реНрдЧреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрд┐рдиреНрд╣реЗрдВ рд╡рд┐рд╕реНрддрд╛рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (рдпрд╣ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛рдУрдВ рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдЧрд╛ рдФрд░ рдореВрд▓ рд░реВрдк рд╕реЗ рдПрдХ рд╡рд░реНрдЧ рдореЗрдВ рд░рдгрдиреАрддрд┐ рдФрд░ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИ):

class LocalStrategy {
  constructor(app);
  async findUser(authParams);
  async comparePassword(user, password);
  async authenticate (authParams);
}

class MyLocalStrategy extends LocalStrategy {
  async findUser(authParams);
}

app.authentication.registerStrategy('local', new MyLocalStrategy(app));

HTTP рдкрд╛рд░реНрд╕рд┐рдВрдЧ

рдПрдХ рд░рдгрдиреАрддрд┐ рдПрдХ parse рд╡рд┐рдзрд┐ рднреА рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреА рд╣реИ рдЬреЛ рдореВрд▓ рдиреЛрдб HTTP рдЕрдиреБрд░реЛрдз рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдЧреА рдФрд░ params.authentication (рдпрд╛ null ) рдХреЗ рд▓рд┐рдП рдореВрд▓реНрдп рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП:

const daveStrategy = {
  async authenticate (authParams) {
    throw new Forbidden('Not super Dave');
  }

  async parse (req, res) {
    const apiKey = req.headers['x-super-dave'];

    if (apiKey) {
      return {
        strategy: 'superdave',
        apiKey
      }
    }

    return null;
  }
};

HTTP рдкреБрд╕реНрддрдХрд╛рд▓рдп рддрдм рддрдп рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╡реЗ params.authentication рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдпрд╛ рдирд╣реАрдВ рдпрд╛ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдХреЛ рдкреНрд░рдорд╛рдгрд┐рдд рдХрд░рддреЗ рд╣реИрдВред

рдРрдк.рдкреНрд░рдорд╛рдгреАрдХрд░рдг

app.authenticate(authParams, [ strategies ]) рджрд┐рдП рдЧрдП рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рджреА рдЧрдИ рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреЛ рдЪрд▓рд╛рдПрдЧрд╛:

// Will return the user for a JWT (on the server)
const { user } = app.authenticate({ accessToken }, 'jwt');

рд╕реЗрд╡рд╛ рдХреЙрд▓ рдореЗрдВ params.authentication рд╕реЗрдЯ рдХрд░рдирд╛ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХрд╛ _only_ рддрд░реАрдХрд╛ рд╣реЛрдЧрд╛ред

рдХреНрдпрд╛ рдЖрдк рдбрд┐рдЬрд╝рд╛рдЗрди рдмрд┐рдВрджреБрдУрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪрд▓ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ service() рдХреЙрд▓ рдкрд░ accessToken рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдХреНрдпреЛрдВ рдЖрд╡рд╢реНрдпрдХ рдерд╛?

рдпрд╣ рдХреЗрд╡рд▓ рд╕рд░реНрд╡рд░ рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдЬреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА params.provider рдФрд░ params.headers рдорд╛рдзреНрдпрдо рд╕реЗ рд╣реЛрддрд╛ рд╣реИ (рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдпрд╣ рдХреЗрд╡рд▓ рдирдХрд▓реА рд╢реАрд░реНрд╖рд▓реЗрдЦ рд╣реИрдВ) рдЬреЛ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдкреНрд░рддреНрдпреЗрдХ рд╕реЗрд╡рд╛ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдпрд╣ рдкрд░рд┐рд╡рд╣рди рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рд╕реНрд╡рддрдВрддреНрд░ рд╣реБрдХ рдФрд░ рд╕реЗрд╡рд╛рдУрдВ рдФрд░ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкрд░рд┐рд╡рд╣рди рддрдВрддреНрд░ (рдЬреИрд╕реЗ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдпрд╛ рд╕реЙрдХреЗрдЯ рдХреЗ рд╕рд╛рде HTTP) рдХреЗ рдмреАрдЪ рдкрдВрдЦ рдЕрд▓рдЧрд╛рд╡ рдХреЛ рддреЛрдбрд╝ рд░рд╣рд╛ рдерд╛ рдФрд░ рдЗрд╕реЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рднреНрд░рдорд┐рдд рдХрд░ рджрд┐рдпрд╛ рдЬрдм рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП authenticate('jwt') рд╣реБрдХ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЪрд▓рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ рдЗрд╕рдХреА рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЬрд╛рдирдХрд╛рд░реАред

рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдмрд╛рд╣рд░реА рдпрд╛ рдЖрдВрддрд░рд┐рдХ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдмрджрд▓реЗрдЧрд╛, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдЕрдм рд╕рд░реНрд╡рд░ рдкрд░ authenticate рд╣реБрдХ рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рд╣рдореЗрд╢рд╛ params.authentication рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдирдП рдлреНрд░реЗрдорд╡рд░реНрдХ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдХреЛрдЖ, рдПрдЪрдЯреАрдЯреАрдкреА 2 рдпрд╛ рдореИрд╕реЗрдЬрд┐рдВрдЧ рдХрддрд╛рд░) рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рдЕрдм рдЕрдкрдиреА рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдкрдВрдЦ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рддрдВрддреНрд░ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдорд╛рдирдХреАрдХреГрдд рддрд░реАрдХрд╛ рд╣реИред

рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдХ рдмрд╛рд░ рд▓реЙрдЧ рдЗрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рднреА app.authenticate() рдХреЙрд▓ рдХрд░рдХреЗ рдкреНрд░рдорд╛рдгрд┐рдд рдЕрдиреБрд░реЛрдз рдХрд░реЗрдЧрд╛ред

рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред v3 рдХреЗ рд╕рд╛рде рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЙрддреНрд╕реБрдХ рд╣реИрдВ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ socket.io рд░рд┐рдПрдХреНрдЯ рдиреЗрдЯрд┐рд╡ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд╕рд╛рдеред

рдкреВрд░реНрд╡-рд░рд┐рд▓реАрдЬрд╝ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдпрд╣рд╛рдБ рдЕрд╡рд╢реНрдп рдбрд╛рд▓реЗрдВрдЧреЗред рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдмрд╕ рд▓рдкреЗрдЯрдирд╛ рдЬреЛ рдкреНрд░рдорд╛рдгреАрдХреГрдд websockets рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред рдПрдХ рдмрд╛рд░ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдирдП рдХреЛрд░ + рд╕реНрдерд╛рдиреАрдп рдФрд░ рдЬреЗрдбрдмреНрд▓реНрдпреВрдЯреА рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдореЗрдВ рдХреБрдЫ рдорджрдж рдХрд░рдирд╛ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред рдЙрд╕рдХреЗ рдмрд╛рдж рдЬрд▓реНрдж рд╣реА oAuth рдХрд╛ рдкрд╛рд▓рди рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЬрдм рд╕рдВрд╕реНрдХрд░рдг 3 рдмрд╛рд╣рд░ рдЖрддрд╛ рд╣реИ?

рдореЗрд░реЗ рд╕рд╡рд╛рд▓ рдХрд╛ рдХреЛрдИ рдЬрд╡рд╛рдм?

рдЖрдк рдорд╛рд╕реНрдЯрд░ рд╢рд╛рдЦрд╛ рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдкреНрд░рдЧрддрд┐ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЬрдм рдмреАрдЯрд╛ рдЯреЗрд╕реНрдЯрд░ рдЗрд╕реЗ рдЖрдЬрдорд╛ рд╕рдХрддреЗ рд╣реИрдВ рддреЛ рдореИрдВ рдПрдХ рдмреНрд▓реЙрдЧ рдкреЛрд╕реНрдЯ рдбрд╛рд▓реВрдВрдЧрд╛ред рд╕реНрдерд┐рддрд┐ рд╣реИ:

| рдореЙрдбреНрдпреВрд▓ | рдХреЛрдб | рдбреЙрдХреНрд╕ | рд╕реАрдПрд▓рдЖрдИ
| --- |:---:|:---:|---:|
| @Federsjs/рдкреНрд░рдорд╛рдгреАрдХрд░рдг | | 100% | |
| @Federsjs/рдкреНрд░рдорд╛рдгреАрдХрд░рдг-рд╕реНрдерд╛рдиреАрдп | | 80% | |
| @рдлреЗрджрд░рдЬрд╕/рдкреНрд░рдорд╛рдгреАрдХрд░рдг-рд╢рдкрде | | 90%| |
| @рдлреЗрджрд░рдЬрд╕/рдкреНрд░рдорд╛рдгреАрдХрд░рдг-рдХреНрд▓рд╛рдЗрдВрдЯ | | 80%| |

рдирдорд╕реНрддреЗ, рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ!

рднрд╡рд┐рд╖реНрдп рдХрд╛ рд▓рдЪреАрд▓рд╛рдкрди рдЕрдЪреНрдЫрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЕрднреА рддрдХ рдЕрдкрдиреЗ рдлреЗрджрд░рдЬреЗрдПрд╕ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдСрде рдХреЗ рд╕рд╛рде рд╡рд┐рд╢реНрд╡рд╛рд╕ рдирд╣реАрдВ рд╣реИ рдФрд░ рдореИрдВ рдЗрд╕реЗ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рднреНрд░рдорд┐рдд рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╕реЗ рдЧреБрдЬрд░ рд░рд╣рд╛ рд╣реВрдВред

рдПрдХ рдкреВрд░реНрдг, рдкрд░реАрдХреНрд╖рдг рдФрд░ рд╕реБрд░рдХреНрд╖рд┐рдд рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реЛрдиреЗ рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдореИрдВ рдЖрддреНрдорд╡рд┐рд╢реНрд╡рд╛рд╕ рд╕реЗ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдкрд░ рдЖрдЧреЗ рдмрдврд╝ рд╕рдХрддрд╛ рд╣реВрдВред MeteorJS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд╕рд░реНрд╡реЛрддреНрддрдо рдХрд╛рд░рдгреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдЧреНрд░рд╛рд╣рдХ рдХреЗ рд▓рд┐рдП рд╕рднреА рддрд░рд╣ рд╕реЗ рдЙрддреНрдХреГрд╖реНрдЯ рдЦрд╛рддреЛрдВ рдХрд╛ рдПрдХреАрдХрд░рдг рдерд╛ред

рдлреЗрджрд░рдЬреЗрдПрд╕ рдореБрджреНрджреЛрдВ рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП, рдХрдИ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдЗрд╕ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдЙрддреНрд╕рд╛рд╣рд┐рдд рд╣реВрдВ!

рдЖрдЬ FeatherJS рдореЗрдВ рдПрдХ рдкреВрд░реНрдг рд╕реБрд░рдХреНрд╖рд┐рдд рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдкреНрд░рдгрд╛рд▓реА (рд╕реНрдерд╛рдиреАрдп рдкреНрд░рдорд╛рдгреАрдХрд░рдг, рдЕрднрд┐рдЧрдо рдирд┐рдпрдВрддреНрд░рдг, рдИрдореЗрд▓, рдЖрджрд┐) рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг (рдпрд╛ рд╕рдВрджрд░реНрдн рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди) рдХрд╣рд╛рдБ рд╣реИ?

рдореЗрд░реЗ рдкрд╛рд╕ рдЕрдм рддрдХ рдпрд╣реА рд╣реИ - рдХреНрдпрд╛ рдХреБрдЫ рдмреЗрд╣рддрд░ рд╣реИ?

2018/02 - рдлреЗрджрд░рдЬреЗрдПрд╕ рдореЗрдВ рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреА рд╕реНрдерд╛рдкрдирд╛ (2017 рд▓реЗрдЦ рдХрд╛ рдкреБрдирд░реНрд▓реЗрдЦрди)
2018/02 - рдЙрдкрд░реЛрдХреНрдд рд▓реЗрдЦ рд╕реЗ рд░реЗрдкреЛ
2017/01 - рдлреЗрджрд░рдЬреЗрдПрд╕ рдореЗрдВ рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреИрд╕реЗ рд╕реЗрдЯрдЕрдк рдХрд░реЗрдВ (рдЯреВрдЯрд╛ рд╣реБрдЖ)
2018/06 - рдкрдВрдЦ рдХреЗ рд╕рд╛рде рд╕рддреНрдпрд╛рдкрди рдкреНрд░рдорд╛рдгреАрдХрд░рдг

рдЕрдЧреНрд░рд┐рдо рдореЗрдВ рдзрдиреНрдпрд╡рд╛рдж!

рд╕рднреА рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ рдХреЛ рдЕрдм рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рд╕рднреА рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд╕рд╛рде рдлреЗрджрд░реНрд╕ v4 рдХреЗ рд▓рд┐рдП рдкреВрд░реНрд╡-рд░рд┐рд▓реАрдЬрд╝ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рд╣реИред рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдЧрд╛рдЗрдб рджреЗрдЦреЗрдВред

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

Vincz picture Vincz  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

codeus-de picture codeus-de  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

arve0 picture arve0  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

huytran0605 picture huytran0605  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

davigmacode picture davigmacode  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ