{"id":373306,"date":"2024-05-21T05:33:10","date_gmt":"2024-05-21T05:33:10","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=373306"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-21T05:33:10","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=373306","title":{"rendered":"<span>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f go \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u043e\u043a\u0435\u043d\u043e\u0432 PASETO<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/367\/3cb\/a02\/3673cba02c33fc9bf52b7dae26c788fc.jpg\" width=\"780\" height=\"440\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/367\/3cb\/a02\/3673cba02c33fc9bf52b7dae26c788fc.jpg\" data-blurred=\"true\"\/><\/figure>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430 go \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u043e\u043a\u0435\u043d\u043e\u0432 PASETO. \u042d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u043e JWT \u0434\u043b\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c \u043e PASETO \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 <a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/790576\/\"><u>\u0425\u0430\u0431\u0440\u0435<\/u><\/a> \u0438\u043b\u0438 <a href=\"https:\/\/github.com\/paseto-standard\/paseto-spec\"><u>\u0433\u0438\u0442\u0445\u0430\u0431\u0435<\/u><\/a>.<\/p>\n<h2>\u0412\u044b\u0431\u043e\u0440 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 PASETO<\/h2>\n<p>\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f PASETO \u0438\u043c\u0435\u0435\u0442 4 \u0432\u0435\u0440\u0441\u0438\u0438, 1 \u0438 2 \u0438\u0437 \u043d\u0438\u0445 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0432\u0430\u0436\u043d\u043e \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 3 \u0438\u043b\u0438 4.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0413\u0443\u0433\u043b \u0438 \u0433\u0438\u0442\u0445\u0430\u0431 \u043f\u0440\u0438 \u043f\u043e\u0438\u0441\u043a\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f Go \u0432 \u043f\u0435\u0440\u0432\u044b\u0445 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u044b\u0434\u0430\u044e\u0442 \u044d\u0442\u043e\u0442 <a href=\"https:\/\/github.com\/o1egl\/paseto\"><u>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/u><\/a>. \u041d\u043e \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 PASETO 1 \u0438 2, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0435\u0439\u0447\u0430\u0441 \u0435\u0433\u043e \u0443\u0436\u0435 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 (\u0430\u043f\u0440\u0435\u043b\u044c 2024 \u0433\u043e\u0434\u0430) \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u0442\u043e\u043a\u0435\u043d\u0430. \u0412\u043e\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 <a href=\"https:\/\/github.com\/aidantwoods\/go-paseto\"><u>\u043f\u0435\u0440\u0432\u044b\u0439<\/u><\/a> \u0438 <a href=\"https:\/\/github.com\/vk-rv\/pvx\"><u>\u0432\u0442\u043e\u0440\u043e\u0439<\/u><\/a>.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438:<\/p>\n<p>1. <a href=\"http:\/\/github.com\/gofiber\/fiber\"><u>github.com\/gofiber\/fiber<\/u><\/a> \u2014 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>2.<a href=\"http:\/\/github.com\/spf13\/viper\"><u> github.com\/spf13\/viper<\/u><\/a> \u2014 \u0447\u0442\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0430.<\/p>\n<p>3. <a href=\"http:\/\/github.com\/stretchr\/testify\"><u>github.com\/stretchr\/testify<\/u><\/a> \u2014 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>4. <a href=\"http:\/\/github.com\/vk-rv\/pvx\"><u>github.com\/vk-rv\/pvx <\/u><\/a>\u00a0\u00a0\u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 PASETO \u0442\u043e\u043a\u0435\u043d\u043e\u0432.<\/p>\n<h2>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c<\/h2>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <code>.env<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u0437\u0430\u0434\u0430\u0435\u043c \u0442\u0440\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445: \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0432\u0440\u0435\u043c\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0438 \u0430\u0434\u0440\u0435\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"go\">TOKEN_KEY=000f3e5799296cc4ce32c444cfde4962 TOKEN_DURATION=60m Address=localhost:4444<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0438\u0436\u0435:  <\/p>\n<pre><code class=\"go\">package appconfig   import (    \"github.com\/spf13\/viper\"    \"time\" )   type Config struct {    TokenKey      string        `mapstructure:\"TOKEN_KEY\"`    TokenDuration time.Duration `mapstructure:\"TOKEN_DURATION\"`    Address       string        `mapstructure:\"ADDRESS\"` }   func Load(path string) (config *Config, err error) {      viper.SetConfigFile(path)      err = viper.ReadInConfig()    if err != nil {        return    }      err = viper.Unmarshal(&amp;config)    return }<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0443 \u043f\u043e\u043b\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0433\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0430. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0447\u0442\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u044c \u0444\u0430\u0439\u043b\u0430 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c \u0438 \u0430\u043d\u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043c \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>Config<\/code>.  <\/p>\n<h2>\u041c\u043e\u0434\u0443\u043b\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c PASETO  <\/h2>\n<p>\u041c\u043e\u0434\u0443\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u043f\u043e \u043f\u0443\u0442\u0438 <code>internal\/auth\/paseto.go<\/code>. \u0421\u0442\u043e\u0438\u0442 \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0443 PASETO \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0440\u0435\u0436\u0438\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b: local \u0438 public. \u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u043e\u043a\u0435\u043d \u0448\u0438\u0444\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c \u0438 \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u0440\u043e\u0447\u0435\u0441\u0442\u044c \u0431\u0435\u0437 \u043a\u043b\u044e\u0447\u0430. \u0412\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u043e\u043a\u0435\u043d \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0430\u0441\u0441\u0438\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c, \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0447\u0435\u0441\u0442\u044c, \u043d\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 local \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 4 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>PasetoAuth<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043a\u043b\u044e\u0447 \u0432 \u0432\u0438\u0434\u0435 \u0441\u043b\u0430\u0439\u0441\u0430 \u0431\u0430\u0439\u0442 \u0438 \u043a\u043b\u044e\u0447 \u0438\u0437 \u043f\u0430\u043a\u0435\u0442\u0430 PASETO. \u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u0435\u0440\u0441\u0438\u044e \u0442\u043e\u043a\u0435\u043d\u0430 \u0438 \u043a\u043b\u044e\u0447. <strong>\u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u0438\u043d\u0430 \u043a\u043b\u044e\u0447\u0430 \u0431\u044b\u043b\u0430 \u0440\u043e\u0432\u043d\u043e 32 \u0431\u0430\u0439\u0442\u0430<\/strong>, \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/github.com\/paseto-standard\/paseto-spec\/blob\/master\/docs\/01-Protocol-Versions\/Version4.md\"><u>\u0442\u0443\u0442<\/u><\/a>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0437\u0430\u0434\u0430\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u043a\u043b\u044e\u0447\u0430 \u0438 \u043e\u0448\u0438\u0431\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u0435\u0434\u0451\u0442 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443 \u043a\u043b\u044e\u0447\u0430. \u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>NewPaseto<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0432 \u043d\u0435\u0439 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440.<\/p>\n<pre><code class=\"go\">package auth   import (    \"fmt\"    \"github.com\/vk-rv\/pvx\"    \"pasetoservice\/internal\/models\"    \"time\" )   type PasetoAuth struct {    pasetoKey    *pvx.SymKey    symmetricKey []byte }   const keySize = 32   var ErrInvalidSize = fmt.Errorf(\"bad key size: it must be %d bytes\", keySize)   func NewPaseto(key []byte) (*PasetoAuth, error) {      if len(key) != keySize {        return nil, ErrInvalidSize    }      pasetoKey := pvx.NewSymmetricKey(key, pvx.Version4)      return &amp;PasetoAuth{        symmetricKey: key,        pasetoKey:    pasetoKey,    }, nil }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u0434 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 <code>internal\/models<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>ServiceClaims<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433\u0430\/\u0430\u043d\u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0442\u043e\u043a\u0435\u043d\u044b. \u041f\u043e\u043b\u0435 <code>pvx.RegisteredClaims<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c, \u0442. \u043a. \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u043d\u0451\u043c \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u0414\u0430\u043b\u0435\u0435 \u0438\u0434\u0435\u0442 \u043f\u043e\u043b\u0435 <code>AdditionalClaims<\/code>, \u0432 \u043d\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0432 PASETO. \u0417\u0430\u0442\u0435\u043c \u0438\u0434\u0451\u0442 <code>Footer<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0444\u0443\u0442\u0435\u0440\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u044d\u0442\u0430 \u0447\u0430\u0441\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0435 \u0448\u0438\u0444\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <code>pvx.RegisteredClaims<\/code> \u0438 <code>AdditionalClaims<\/code>.<\/p>\n<pre><code class=\"go\">\/\/internal\/models\/models.go type AdditionalClaims struct {    Name string `json:\"name\"`    Role string `json:\"role\"` }   type Footer struct {    MetaData string `json:\"meta_data\"` }  type ServiceClaims struct {    pvx.RegisteredClaims    AdditionalClaims    Footer }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u043e\u0432.\u00a0\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432, \u0442. \u043a. \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u044f <code>IssuedAt<\/code> \u0438 <code>Expiration<\/code>, \u0430 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u2014 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u043e\u043b\u044f. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:  <\/p>\n<pre><code class=\"go\">type TokenData struct {    Subject  string    Duration time.Duration    AdditionalClaims    Footer }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043e\u0431\u044a\u0435\u043a\u0442 <code>serviceClaims<\/code>, \u0434\u0430\u043b\u0435\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u043e\u043b\u044f <code>IssuedAt<\/code> \u0438 <code>Expiration<\/code>, \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0443\u0436\u0435 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>pvx.NewPV4Local()<\/code>, \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 local \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 4 \u0432\u0435\u0440\u0441\u0438\u0438. \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>Encrypt<\/code> \u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e 2 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430: \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438 <code>serviceClaims<\/code>, \u0444\u0443\u0442\u0435\u0440 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c. \u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>Encrypt<\/code> \u0432\u0435\u0440\u043d\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438.  <\/p>\n<pre><code class=\"go\">func (pa *PasetoAuth) NewToken(data models.TokenData) (string, error) {      serviceClaims := &amp;models.ServiceClaims{}      iss := time.Now()    exp := iss.Add(data.Duration)      serviceClaims.IssuedAt = &amp;iss    serviceClaims.Expiration = &amp;exp    serviceClaims.Subject = data.Subject      serviceClaims.AdditionalClaims = data.AdditionalClaims    serviceClaims.Footer = data.Footer      pv4 := pvx.NewPV4Local()      authToken, err := pv4.Encrypt(pa.pasetoKey, serviceClaims,        pvx.WithFooter(serviceClaims.Footer))    if err != nil {        return \"\", err    }      return authToken, nil   }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0442\u043e\u043a\u0435\u043d \u043d\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c. \u0414\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>Decrypt<\/code>. \u041f\u043e\u0441\u043b\u0435 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>Scan<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 <code>ServiceClaims<\/code>. Scan \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u0430 \u0438 \u0431\u044b\u043b\u0438 \u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0435.  <\/p>\n<pre><code class=\"go\">func (pa *PasetoAuth) VerifyToken(token string) (*models.ServiceClaims, error) {    pv4 := pvx.NewPV4Local()    tk := pv4.Decrypt(token, pa.pasetoKey)      f := models.Footer{}    sc := models.ServiceClaims{        Footer: f,    }      err := tk.Scan(&amp;sc, &amp;f)    if err != nil {        return &amp;sc, err    }      return &amp;sc, nil }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438. \u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0438 \u0443\u0431\u0435\u0434\u0438\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043e\u043a. \u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u043d\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c, \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u044f \u0438\u043c\u0435\u044e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0438:  <\/p>\n<pre><code class=\"go\">package auth   import (    \"github.com\/stretchr\/testify\/require\"    \"pasetoservice\/internal\/models\"    \"testing\"    \"time\" )   func TestServiceGenerateNewKey(t *testing.T) {      key := []byte(\"000f3e5799296cc4ce32c444cfde4962\")      pasetoToken, err := NewPaseto(key)    require.NoError(t, err)      token, err := pasetoToken.NewToken(models.TokenData{        Subject:  \"test\",        Duration: 5 * time.Second,        AdditionalClaims: models.AdditionalClaims{            Name: \"add name\",            Role: \"test-role\",        },        Footer: models.Footer{MetaData: \"footer\"},    })      require.NoError(t, err)    require.NotEmpty(t, token)      sc, err := pasetoToken.VerifyToken(token)    require.NoError(t, err)    require.Equal(t, \"footer\", sc.Footer.MetaData)    require.Equal(t, \"add name\", sc.AdditionalClaims.Name)    require.Equal(t, \"test-role\", sc.AdditionalClaims.Role)   }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0442\u0435\u0441\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>NewPaseto<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u043f\u0440\u0438 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u0435 \u043a\u043b\u044e\u0447\u0430. \u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>NewToken<\/code>, \u043e\u0431\u044a\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c <code>Duration<\/code> \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0422\u0430\u043a \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u0431\u044f \u0432\u0435\u0441\u0442\u0438 \u0442\u043e\u043a\u0435\u043d \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u0441\u0442\u0435\u0447\u0435\u0442. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043f\u0440\u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430, \u043a\u0430\u043a \u0438 \u043e\u0436\u0438\u0434\u0430\u043b\u043e\u0441\u044c:  <\/p>\n<pre><code class=\"go\">func TestInvalidCases(t *testing.T) {      badKey := []byte(\"00\")    pasetoToken, err := NewPaseto(badKey)    require.ErrorIs(t, err, ErrInvalidSize)      key := []byte(\"000f3e5799296cc4ce32c444cfde4962\")    pasetoToken, err = NewPaseto(key)    require.NoError(t, err)      token, err := pasetoToken.NewToken(models.TokenData{        Duration: -5 * time.Second,    })    require.NoError(t, err)      sc, err := pasetoToken.VerifyToken(token)    require.Error(t, err)    require.Error(t, sc.Valid())   }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e API, \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>internal\/api<\/code> \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0432 \u0444\u0430\u0439\u043b\u0435 server.go:  <\/p>\n<pre><code class=\"go\">type App struct {    token     *auth.PasetoAuth    routerApi *fiber.App    config    *appconfig.Config }<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043e\u0439 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u043e\u0432. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e middleware. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 <code>middleware.go<\/code>:  <\/p>\n<pre><code class=\"go\">package api   import (    \"errors\"    \"fmt\"    \"github.com\/gofiber\/fiber\/v2\"    \"strings\" )   const (    authHeader = \"Authorization\"    typeBearer = \"bearer\" )   var (    ErrMissingAuthHeader = errors.New(\"authorization header is missing\")    ErrInvalidAuthHeader = errors.New(\"invalid authorization header\") )   func (a *App) CheckAuth() fiber.Handler {    return func(c *fiber.Ctx) error {        authVal := c.Get(authHeader)          if len(authVal) == 0 {            return c.Status(fiber.StatusUnauthorized).                JSON(fiber.Map{\"error\": ErrMissingAuthHeader.Error()})        }          splitHeader := strings.Fields(authVal)          if len(splitHeader) &lt; 2 {            return c.Status(fiber.StatusUnauthorized).                JSON(fiber.Map{\"error\": ErrInvalidAuthHeader.Error()})        }          authType := strings.ToLower(splitHeader[0])        if authType != typeBearer {            err := fmt.Errorf(\"unsupported authorization type %s\", authType)            return c.Status(fiber.StatusUnauthorized).                JSON(fiber.Map{\"error\": err.Error()})        }          claims, err := a.token.VerifyToken(splitHeader[1])        if err != nil {            return c.Status(fiber.StatusUnauthorized).                JSON(fiber.Map{\"error\": err.Error()})        }          c.Locals(\"claims\", claims)          return c.Next()    } }<\/code><\/pre>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 Authorization. \u0412 <code>middleware<\/code> \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d \u0438 \u0441\u0445\u0435\u043c\u0443. \u0415\u0441\u043b\u0438 \u043d\u0430\u043c \u044d\u0442\u043e \u043d\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044f, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 401 (Unauthorized) \u0438 \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0415\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u043f\u0440\u043e\u0448\u0435\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443, \u0442\u043e \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\/\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 <code>ServiceClaims<\/code>, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0438 \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>users.go<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b API: <\/p>\n<pre><code class=\"go\">package api  var users = map[string]string{    \"user\":  \"user\",    \"admin\": \"admin\", }<\/code><\/pre>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 Login, \u0435\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u044b\u0434\u0430\u0447\u0438 \u043d\u043e\u0432\u044b\u0445 \u0442\u043e\u043a\u0435\u043d\u043e\u0432. \u0414\u0430\u043d\u043d\u044b\u0439 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 <code>paseto_handlers.go<\/code>.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0430, \u0432 \u0444\u0430\u0439\u043b <code>models\/models.go<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043c\u0435\u0449\u0430\u0442\u044c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0444\u043e\u0440\u043c:<\/p>\n<pre><code class=\"go\">type Credentials struct {    Password string `form:\"password\"`    Username string `form:\"username\"` }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0445\u044d\u043d\u0434\u043b\u0435\u0440 Login. \u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0435\u0441\u043b\u0438 \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043a\u043e\u0434 400 (Bad Request). \u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0444\u043e\u0440\u043c \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u043b\u0438\u0441\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438 \u0447\u0442\u043e \u0435\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044c \u0432\u0435\u0440\u043d\u044b\u0439. \u0415\u0441\u043b\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c 401 (Unauthorized).\u00a0<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0442\u043e\u043a\u0435\u043d. <code>Duration<\/code> \u043c\u044b \u0431\u0435\u0440\u0451\u043c \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u043c\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043b\u0438\u0431\u043e \u043e\u0448\u0438\u0431\u043a\u0443 \u0441\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u043c 500 (Internal Server Error), \u043b\u0438\u0431\u043e \u0441\u0442\u0430\u0442\u0443\u0441 200 (OK) \u0438 \u0442\u043e\u043a\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438:<\/p>\n<pre><code class=\"go\">package api   import (    \"github.com\/gofiber\/fiber\/v2\"    \"pasetoservice\/internal\/models\" )   func (a *App) Login(c *fiber.Ctx) error {    var creds models.Credentials      if err := c.BodyParser(&amp;creds); err != nil {        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{\"error\": err.Error()})    }      expectedPass, ok := users[creds.Username]    if !ok || expectedPass != creds.Password {        return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{\"error\": \"bad password or username\"})    }      pasetoToken, err := a.token.NewToken(models.TokenData{        Subject:  \"for user\",        Duration: a.config.TokenDuration,        AdditionalClaims: models.AdditionalClaims{            Name: creds.Username,            Role: creds.Username,        },        Footer: models.Footer{MetaData: \"footer for \" + creds.Username},    })      if err != nil {        return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{\"error\": err.Error()})    }      return c.Status(fiber.StatusOK).JSON(fiber.Map{\"token\": pasetoToken}) } <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e API \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>NewApp<\/code> \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0442\u0438\u043f\u043e\u043c <code>*fiber.App<\/code>. \u0414\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0431\u0443\u0434\u0443\u0442 \u0438\u043c\u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 url, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043a \u043d\u0438\u043c \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f:  <\/p>\n<pre><code class=\"go\">package api   import (    \"fmt\"    \"github.com\/gofiber\/fiber\/v2\"    \"pasetoservice\/internal\/appconfig\"    \"pasetoservice\/internal\/auth\"    \"pasetoservice\/internal\/models\" )   type App struct {    token     *auth.PasetoAuth    routerApi *fiber.App    config    *appconfig.Config }   func NewApp(c *appconfig.Config, routerApi *fiber.App) (*App, error) {      pasetoToken, err := auth.NewPaseto([]byte(c.TokenKey))    if err != nil {        return nil, err    }      app := &amp;App{        token:     pasetoToken,        routerApi: routerApi,        config:    c,    }      app.SetApi()      return app, nil } <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>SetApi<\/code> \u0443 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b App, \u0432 \u043d\u0435\u043c \u043c\u044b \u0437\u0430\u0434\u0430\u0434\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u044b \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:  <\/p>\n<pre><code class=\"go\">func (a *App) SetApi() {    a.routerApi.Post(\"\/login\", a.Login)      protectedApi := a.routerApi.Group(\"\/api\", a.CheckAuth())      protectedApi.Get(\"\/account\", func(c *fiber.Ctx) error {          val := c.Locals(\"claims\")          v, ok := val.(*models.ServiceClaims)          if !ok {            return c.Status(fiber.StatusInternalServerError). JSON(fiber.Map{\"error\": \"type conversion error\"})        }          fmt.Printf(\"%#v\", v)          owner := fmt.Sprintf(\"&lt;h3>Account owner - %s&lt;\/h3>\", v.Name)        role := fmt.Sprintf(\"&lt;h3>Account role - %s&lt;\/h3>\", v.Role)        footer := fmt.Sprintf(\"&lt;h3>Account footer - %s&lt;\/h3>\", v.MetaData)          return c.SendString(owner + role + footer)    })   }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0430 <code>\/login<\/code> \u043c\u044b \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438 \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0443. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u201c\u0433\u0440\u0443\u043f\u043f\u0443\u201d <code>\/api<\/code> . \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u043b\u044e\u0431\u043e\u0439 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0430 \u0432 \u044d\u0442\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0430\u0448\u0435 middleware CheckAuth(), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0414\u0430\u043b\u0435\u0435 \u0432 \u0433\u0440\u0443\u043f\u043f\u0443 \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0445\u0435\u043d\u0434\u043b\u0435\u0440 <code>\/account<\/code>, \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a \u0432 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0435 account \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0438 \u0437\u0430\u0442\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0435\u0433\u043e \u043f\u043e\u043b\u0435\u0439 \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435.\u00a0<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e Start \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code class=\"go\">func (a *App) Start() error {    return a.routerApi.Listen(a.config.Address) }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 main. \u0412 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u044b \u0447\u0438\u0442\u0430\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0442\u0438\u043f\u0430 <code>*fiber.App<\/code>, \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441.  <\/p>\n<pre><code class=\"go\">package main   import (    \"github.com\/gofiber\/fiber\/v2\"    \"log\"    \"pasetoservice\/internal\/api\"    \"pasetoservice\/internal\/appconfig\" )   func main() {      c, err := appconfig.Load(\".env\")    if err != nil {        log.Fatal(\"can't load config:\", err)    }      routerApi := fiber.New()    app, err := api.NewApp(c, routerApi)    if err != nil {        log.Fatal(\"create app error:\", err)    }    app.SetApi()    log.Fatal(app.Start())   }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Postman \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u043e\u043a\u0435\u043d \u0434\u043b\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043c POST \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <em>localhost:4444\/login<\/em> \u0438 \u0432 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0444\u043e\u0440\u043c\u044b \u0441 \u043b\u043e\u0433\u0438\u043d\u043e\u043c \u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0440\u0438\u0441\u0443\u043d\u043a\u0435 \u043d\u0438\u0436\u0435:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fe8\/e36\/8d1\/fe8e368d139c1aaaa6cdf9985dc9027b.png\" width=\"1436\" height=\"633\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fe8\/e36\/8d1\/fe8e368d139c1aaaa6cdf9985dc9027b.png\"\/><\/figure>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u043e\u0439 \u0442\u043e\u043a\u0435\u043d:  <\/p>\n<pre><code class=\"go\">{ \"token\": \"v4.local.v5fH8aPWCaV9VBd5HPnVlSU4kfEf8zHsCAAluI5-9jZsA93D_OLMfSKBJFgd4AUq_X2GjjzjnAZnbGVZiooQKJWV9Fd_YX7X1b5Egj_A7FkMp1CYByeYPFEhsp0CPaaytZdqKpJ5gmcF3TBzPQE9a2Y6Bk648Yc0RiI2cWBwbj8AI61zs0TfwpjvGbf8ENKv6TASBFZbVdrRYFDxizF2Hxgc35OJTXDy37jsS8lmOBhnR0dCJZFP1itfRgDnaNyPUQQbj0gwUteuq7J8cAElIcudvJthfaSPioGx_ibeXFHlKWaAikc1.eyJtZXRhX2RhdGEiOiJmb290ZXIgZm9yIGFkbWluIn0\" } <\/code><\/pre>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0442\u043e\u043a\u0435\u043d\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0444\u0443\u0442\u0435\u0440 (<code>eyJtZXRhX2RhdGEiOiJmb290ZXIgZm9yIGFkbWluIn0<\/code>), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d \u0432 base64. \u0415\u0441\u043b\u0438 \u043c\u044b \u0435\u0433\u043e \u0440\u0430\u0441\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u043c, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u043e\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:  <\/p>\n<pre><code class=\"go\">{ \"meta_data\":\"footer for admin\" }<\/code><\/pre>\n<p>\u0414\u0440\u0443\u0433\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0442. \u043a. \u043e\u043d\u0430 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a Authorization. \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0435\u0437 \u043d\u0435\u0433\u043e \u0438\u043b\u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u0435 \u0442\u0443\u0434\u0430 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d, \u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0435\u0440\u043d\u0435\u0442 \u043a\u043e\u0434 401 \u0438 \u043e\u0448\u0438\u0431\u043a\u0443.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9af\/b6e\/8f5\/9afb6e8f548ab6d5a7bda2b8d6c56af6.png\" width=\"1436\" height=\"633\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9af\/b6e\/8f5\/9afb6e8f548ab6d5a7bda2b8d6c56af6.png\"\/><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a (\u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0443 Bearer \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435) \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u043c\u0443 API. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0440\u0438\u0441\u0443\u043d\u043a\u0435 \u043d\u0438\u0436\u0435.  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a36\/d8c\/be1\/a36d8cbe17745199c43b50776cd68691.png\" width=\"1436\" height=\"633\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a36\/d8c\/be1\/a36d8cbe17745199c43b50776cd68691.png\"\/><\/figure>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/github.com\/syncname\/paseto_service\"><u>\u0442\u0443\u0442<\/u><\/a>.  <\/p>\n<p><strong>\u0410\u0432\u0442\u043e\u0440 \u0441\u0442\u0430\u0442\u044c\u0438\u00a0<\/strong><a href=\"https:\/\/habr.com\/ru\/users\/yurii_habr\/\"><strong>@yurii_habr<\/strong><\/a><\/p>\n<hr\/>\n<p>\u041d\u041b\u041e \u043f\u0440\u0438\u043b\u0435\u0442\u0435\u043b\u043e \u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u043b\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u043c\u043e\u043a\u043e\u0434 \u0434\u043b\u044f \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043b\u043e\u0433\u0430:<br \/><a href=\"https:\/\/firstvds.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=product&amp;utm_content=vds15exeptprogrev\">-15% \u043d\u0430 \u0437\u0430\u043a\u0430\u0437 \u043b\u044e\u0431\u043e\u0433\u043e VDS<\/a>\u00a0(\u043a\u0440\u043e\u043c\u0435 \u0442\u0430\u0440\u0438\u0444\u0430 \u041f\u0440\u043e\u0433\u0440\u0435\u0432) \u2014\u00a0<strong>HABRFIRSTVDS<\/strong>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/806871\/\"> https:\/\/habr.com\/ru\/articles\/806871\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430 go \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u043e\u043a\u0435\u043d\u043e\u0432 PASETO. \u042d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u043e JWT \u0434\u043b\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c \u043e PASETO \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 <a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/790576\/\"><u>\u0425\u0430\u0431\u0440\u0435<\/u><\/a> \u0438\u043b\u0438 <a href=\"https:\/\/github.com\/paseto-standard\/paseto-spec\"><u>\u0433\u0438\u0442\u0445\u0430\u0431\u0435<\/u><\/a>.<\/p>\n<h2>\u0412\u044b\u0431\u043e\u0440 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 PASETO<\/h2>\n<p>\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f PASETO \u0438\u043c\u0435\u0435\u0442 4 \u0432\u0435\u0440\u0441\u0438\u0438, 1 \u0438 2 \u0438\u0437 \u043d\u0438\u0445 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0432\u0430\u0436\u043d\u043e \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 3 \u0438\u043b\u0438 4.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0413\u0443\u0433\u043b \u0438 \u0433\u0438\u0442\u0445\u0430\u0431 \u043f\u0440\u0438 \u043f\u043e\u0438\u0441\u043a\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f Go \u0432 \u043f\u0435\u0440\u0432\u044b\u0445 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u044b\u0434\u0430\u044e\u0442 \u044d\u0442\u043e\u0442 <a href=\"https:\/\/github.com\/o1egl\/paseto\"><u>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/u><\/a>. \u041d\u043e \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 PASETO 1 \u0438 2, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0435\u0439\u0447\u0430\u0441 \u0435\u0433\u043e \u0443\u0436\u0435 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 (\u0430\u043f\u0440\u0435\u043b\u044c 2024 \u0433\u043e\u0434\u0430) \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u0442\u043e\u043a\u0435\u043d\u0430. \u0412\u043e\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 <a href=\"https:\/\/github.com\/aidantwoods\/go-paseto\"><u>\u043f\u0435\u0440\u0432\u044b\u0439<\/u><\/a> \u0438 <a href=\"https:\/\/github.com\/vk-rv\/pvx\"><u>\u0432\u0442\u043e\u0440\u043e\u0439<\/u><\/a>.\u00a0<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438:<\/p>\n<p>1. <a href=\"http:\/\/github.com\/gofiber\/fiber\"><u>github.com\/gofiber\/fiber<\/u><\/a> \u2014 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>2.<a href=\"http:\/\/github.com\/spf13\/viper\"><u> github.com\/spf13\/viper<\/u><\/a> \u2014 \u0447\u0442\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0430.<\/p>\n<p>3. <a href=\"http:\/\/github.com\/stretchr\/testify\"><u>github.com\/stretchr\/testify<\/u><\/a> \u2014 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>4. <a href=\"http:\/\/github.com\/vk-rv\/pvx\"><u>github.com\/vk-rv\/pvx <\/u><\/a>\u00a0\u00a0\u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 PASETO \u0442\u043e\u043a\u0435\u043d\u043e\u0432.<\/p>\n<h2>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c<\/h2>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <code>.env<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u0437\u0430\u0434\u0430\u0435\u043c \u0442\u0440\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445: \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0432\u0440\u0435\u043c\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0438 \u0430\u0434\u0440\u0435\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"go\">TOKEN_KEY=000f3e5799296cc4ce32c444cfde4962 TOKEN_DURATION=60m Address=localhost:4444<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0438\u0436\u0435:  <\/p>\n<pre><code class=\"go\">package appconfig   import (    \"github.com\/spf13\/viper\"    \"time\" )   type Config struct {    TokenKey      string        `mapstructure:\"TOKEN_KEY\"`    TokenDuration time.Duration `mapstructure:\"TOKEN_DURATION\"`    Address       string        `mapstructure:\"ADDRESS\"` }   func Load(path string) (config *Config, err error) {      viper.SetConfigFile(path)      err = viper.ReadInConfig()    if err != nil {        return    }      err = viper.Unmarshal(&amp;config)    return }<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0443 \u043f\u043e\u043b\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0433\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0430. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0447\u0442\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u044c \u0444\u0430\u0439\u043b\u0430 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c \u0438 \u0430\u043d\u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043c \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>Config<\/code>.  <\/p>\n<h2>\u041c\u043e\u0434\u0443\u043b\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c PASETO  <\/h2>\n<p>\u041c\u043e\u0434\u0443\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u043f\u043e \u043f\u0443\u0442\u0438 <code>internal\/auth\/paseto.go<\/code>. \u0421\u0442\u043e\u0438\u0442 \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0443 PASETO \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0440\u0435\u0436\u0438\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b: local \u0438 public. \u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u043e\u043a\u0435\u043d \u0448\u0438\u0444\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c \u0438 \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u0440\u043e\u0447\u0435\u0441\u0442\u044c \u0431\u0435\u0437 \u043a\u043b\u044e\u0447\u0430. \u0412\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u043e\u043a\u0435\u043d \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0430\u0441\u0441\u0438\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c, \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0447\u0435\u0441\u0442\u044c, \u043d\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 local \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 4 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>PasetoAuth<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043a\u043b\u044e\u0447 \u0432 \u0432\u0438\u0434\u0435 \u0441\u043b\u0430\u0439\u0441\u0430 \u0431\u0430\u0439\u0442 \u0438 \u043a\u043b\u044e\u0447 \u0438\u0437 \u043f\u0430\u043a\u0435\u0442\u0430 PASETO. \u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u0435\u0440\u0441\u0438\u044e \u0442\u043e\u043a\u0435\u043d\u0430 \u0438 \u043a\u043b\u044e\u0447. <strong>\u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u0438\u043d\u0430 \u043a\u043b\u044e\u0447\u0430 \u0431\u044b\u043b\u0430 \u0440\u043e\u0432\u043d\u043e 32 \u0431\u0430\u0439\u0442\u0430<\/strong>, \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/github.com\/paseto-standard\/paseto-spec\/blob\/master\/docs\/01-Protocol-Versions\/Version4.md\"><u>\u0442\u0443\u0442<\/u><\/a>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0437\u0430\u0434\u0430\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u043a\u043b\u044e\u0447\u0430 \u0438 \u043e\u0448\u0438\u0431\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u0435\u0434\u0451\u0442 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443 \u043a\u043b\u044e\u0447\u0430. \u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>NewPaseto<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0432 \u043d\u0435\u0439 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440.<\/p>\n<pre><code class=\"go\">package auth   import (    \"fmt\"    \"github.com\/vk-rv\/pvx\"    \"pasetoservice\/internal\/models\"    \"time\" )   type PasetoAuth struct {    pasetoKey    *pvx.SymKey    symmetricKey []byte }   const keySize = 32   var ErrInvalidSize = fmt.Errorf(\"bad key size: it must be %d bytes\", keySize)   func NewPaseto(key []byte) (*PasetoAuth, error) {      if len(key) != keySize {        return nil, ErrInvalidSize    }      pasetoKey := pvx.NewSymmetricKey(key, pvx.Version4)      return &amp;PasetoAuth{        symmetricKey: key,        pasetoKey:    pasetoKey,    }, nil }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u0434 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 <code>internal\/models<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>ServiceClaims<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433\u0430\/\u0430\u043d\u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0442\u043e\u043a\u0435\u043d\u044b. \u041f\u043e\u043b\u0435 <code>pvx.RegisteredClaims<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c, \u0442. \u043a. \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u043d\u0451\u043c \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u0414\u0430\u043b\u0435\u0435 \u0438\u0434\u0435\u0442 \u043f\u043e\u043b\u0435 <code>AdditionalClaims<\/code>, \u0432 \u043d\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0432 PASETO. \u0417\u0430\u0442\u0435\u043c \u0438\u0434\u0451\u0442 <code>Footer<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0444\u0443\u0442\u0435\u0440\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u044d\u0442\u0430 \u0447\u0430\u0441\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0435 \u0448\u0438\u0444\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <code>pvx.RegisteredClaims<\/code> \u0438 <code>AdditionalClaims<\/code>.<\/p>\n<pre><code class=\"go\">\/\/internal\/models\/models.go type AdditionalClaims struct {    Name string `json:\"name\"`    Role string `json:\"role\"` }   type Footer struct {    MetaData string `json:\"meta_data\"` }  type ServiceClaims struct {    pvx.RegisteredClaims    AdditionalClaims    Footer }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u043e\u0432.\u00a0\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432, \u0442. \u043a. \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u044f <code>IssuedAt<\/code> \u0438 <code>Expiration<\/code>, \u0430 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u2014 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u043e\u043b\u044f. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:  <\/p>\n<pre><code class=\"go\">type TokenData struct {    Subject  string    Duration time.Duration    AdditionalClaims    Footer }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043e\u0431\u044a\u0435\u043a\u0442 <code>serviceClaims<\/code>, \u0434\u0430\u043b\u0435\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u043e\u043b\u044f <code>IssuedAt<\/code> \u0438 <code>Expiration<\/code>, \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0443\u0436\u0435 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>pvx.NewPV4Local()<\/code>, \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 local \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 4 \u0432\u0435\u0440\u0441\u0438\u0438. \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>Encrypt<\/code> \u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e 2 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430: \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438 <code>serviceClaims<\/code>, \u0444\u0443\u0442\u0435\u0440 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c. \u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>Encrypt<\/code> \u0432\u0435\u0440\u043d\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438.  <\/p>\n<pre><code class=\"go\">func (pa *PasetoAuth) NewToken(data models.TokenData) (string, error) {      serviceClaims := &amp;models.ServiceClaims{}      iss := time.Now()    exp := iss.Add(data.Duration)      serviceClaims.IssuedAt = &amp;iss    serviceClaims.Expiration = &amp;exp    serviceClaims.Subject = data.Subject      serviceClaims.AdditionalClaims = data.AdditionalClaims    serviceClaims.Footer = data.Footer      pv4 := pvx.NewPV4Local()      authToken, err := pv4.Encrypt(pa.pasetoKey, serviceClaims,        pvx.WithFooter(serviceClaims.Footer))    if err != nil {        return \"\", err    }      return authToken, nil   }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0442\u043e\u043a\u0435\u043d \u043d\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c. \u0414\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>Decrypt<\/code>. \u041f\u043e\u0441\u043b\u0435 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>Scan<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 <code>ServiceClaims<\/code>. Scan \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u0430 \u0438 \u0431\u044b\u043b\u0438 \u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0435.  <\/p>\n<pre><code class=\"go\">func (pa *PasetoAuth) VerifyToken(token string) (*models.ServiceClaims, error) {    pv4 := pvx.NewPV4Local()    tk := pv4.Decrypt(token, pa.pasetoKey)      f := models.Footer{}    sc := models.ServiceClaims{        Footer: f,    }      err := tk.Scan(&amp;sc, &amp;f)    if err != nil {        return &amp;sc, err    }      return &amp;sc, nil }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438. \u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0438 \u0443\u0431\u0435\u0434\u0438\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043e\u043a. \u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u043d\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c, \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u044f \u0438\u043c\u0435\u044e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0438:  <\/p>\n<pre><code class=\"go\">package auth   import (    \"github.com\/stretchr\/testify\/require\"    \"pasetoservice\/internal\/models\"    \"testing\"    \"time\" )   func TestServiceGenerateNewKey(t *testing.T) {      key := []byte(\"000f3e5799296cc4ce32c444cfde4962\")      pasetoToken, err := NewPaseto(key)    require.NoError(t, err)      token, err := pasetoToken.NewToken(models.TokenData{        Subject:  \"test\",        Duration: 5 * time.Second,        AdditionalClaims: models.AdditionalClaims{            Name: \"add name\",            Role: \"test-role\",        },        Footer: models.Footer{MetaData: \"footer\"},    })      require.NoError(t, err)    require.NotEmpty(t, token)      sc, err := pasetoToken.VerifyToken(token)    require.NoError(t, err)    require.Equal(t, \"footer\", sc.Footer.MetaData)    require.Equal(t, \"add name\", sc.AdditionalClaims.Name)    require.Equal(t, \"test-role\", sc.AdditionalClaims.Role)   }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0442\u0435\u0441\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>NewPaseto<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u043f\u0440\u0438 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u0435 \u043a\u043b\u044e\u0447\u0430. \u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>NewToken<\/code>, \u043e\u0431\u044a\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c <code>Duration<\/code> \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0422\u0430\u043a \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u0431\u044f \u0432\u0435\u0441\u0442\u0438 \u0442\u043e\u043a\u0435\u043d \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u0441\u0442\u0435\u0447\u0435\u0442. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043f\u0440\u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430, \u043a\u0430\u043a \u0438 \u043e\u0436\u0438\u0434\u0430\u043b\u043e\u0441\u044c:  <\/p>\n<pre><code class=\"go\">func TestInvalidCases(t *testing.T) {      badKey := []byte(\"00\")    pasetoToken, err := NewPaseto(badKey)    require.ErrorIs(t, err, ErrInvalidSize)      key := []byte(\"000f3e5799296cc4ce32c444cfde4962\")    pasetoToken, err = NewPaseto(key)    require.NoError(t, err)      token, err := pasetoToken.NewToken(models.TokenData{        Duration: -5 * time.Second,    })    require.NoError(t, err)      sc, err := pasetoToken.VerifyToken(token)    require.Error(t, err)    require.Error(t, sc.Valid())   }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e API, \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>internal\/api<\/code> \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0432 \u0444\u0430\u0439\u043b\u0435 server.go:  <\/p>\n<pre><code class=\"go\">type App struct {    token     *auth.PasetoAuth    routerApi *fiber.App    config    *appconfig.Config }<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043e\u0439 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u043e\u0432. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e middleware. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 <code>middleware.go<\/code>:  <\/p>\n<pre><code class=\"go\">package api   import (    \"errors\"    \"fmt\"    \"github.com\/gofiber\/fiber\/v2\"    \"strings\" )   const (    authHeader = \"Authorization\"    typeBearer = \"bearer\" )   var (    ErrMissingAuthHeader = errors.New(\"authorization header is missing\")    ErrInvalidAuthHeader = errors.New(\"invalid authorization header\") )   func (a *App) CheckAuth() fiber.Handler {    return func(c *fiber.Ctx) error {        authVal := c.Get(authHeader)          if len(authVal) == 0 {            return c.Status(fiber.StatusUnauthorized).                JSON(fiber.Map{\"error\": ErrMissingAuthHeader.Error()})        }          splitHeader := strings.Fields(authVal)          if len(splitHeader) &lt; 2 {            return c.Status(fiber.StatusUnauthorized).  <\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-373306","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/373306","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=373306"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/373306\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=373306"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=373306"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=373306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}