成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Laravel 5.5 使用 Jwt-Auth 實(shí)現(xiàn) API 用戶認(rèn)證以及無痛刷新訪問令牌

xavier / 958人閱讀

摘要:默認(rèn)的時間為周。大概意思就是如果用戶有一個,那么他可以帶著他的過來領(lǐng)取新的,直到周的時間后,他便無法繼續(xù)刷新了,需要重新登錄。指定在刷新令牌時要保留的聲明密鑰。為了使令牌無效,您必須啟用黑名單。指定用于對用戶進(jìn)行身份驗(yàn)證的提供程序。

最近在做一個公司的項(xiàng)目,前端使用 Vue.js,后端使用 Laravel 構(gòu)建 Api 服務(wù),用戶認(rèn)證的包本來是想用 Laravel Passport 的,但是感覺有點(diǎn)麻煩,于是使用了 jwt-auth 。

安裝

jwt-auth 最新版本是 1.0.0 rc.1 版本,已經(jīng)支持了 Laravel 5.5。如果你使用的是 Laravel 5.5 版本,可以使用如下命令安裝。根據(jù)評論區(qū) @tradzero 兄弟的建議,如果你是 Laravel 5.5 以下版本,也推薦使用最新版本,RC.1 前的版本都存在多用戶token認(rèn)證的安全問題。

$ composer require tymon/jwt-auth 1.0.0-rc.1
配置 添加服務(wù)提供商

將下面這行添加至 config/app.php 文件 providers 數(shù)組中:

app.php

"providers" => [

    ...

    TymonJWTAuthProvidersLaravelServiceProvider::class,
]
發(fā)布配置文件

在你的 shell 中運(yùn)行如下命令發(fā)布 jwt-auth 的配置文件:

shell

$ php artisan vendor:publish --provider="TymonJWTAuthProvidersLaravelServiceProvider"

此命令會在 config 目錄下生成一個 jwt.php 配置文件,你可以在此進(jìn)行自定義配置。

生成密鑰

jwt-auth 已經(jīng)預(yù)先定義好了一個 Artisan 命令方便你生成 Secret,你只需要在你的 shell 中運(yùn)行如下命令即可:

shell

$ php artisan jwt:secret

此命令會在你的 .env 文件中新增一行 JWT_SECRET=secret

配置 Auth guard

config/auth.php 文件中,你需要將 guards/driver 更新為 jwt

auth.php

"defaults" => [
    "guard" => "api",
    "passwords" => "users",
],

...

"guards" => [
    "api" => [
        "driver" => "jwt",
        "provider" => "users",
    ],
],
只有在使用 Laravel 5.2 及以上版本的情況下才能使用。
更改 Model

如果需要使用 jwt-auth 作為用戶認(rèn)證,我們需要對我們的 User 模型進(jìn)行一點(diǎn)小小的改變,實(shí)現(xiàn)一個接口,變更后的 User 模型如下:

User.php

getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}
配置項(xiàng)詳解

jwt.php

 env("JWT_SECRET"),

    /*
    |--------------------------------------------------------------------------
    | JWT Authentication Keys
    |--------------------------------------------------------------------------
    |
    | 如果你在 .env 文件中定義了 JWT_SECRET 的隨機(jī)字符串
    | 那么 jwt 將會使用 對稱算法 來生成 token
    | 如果你沒有定有,那么jwt 將會使用如下配置的公鑰和私鑰來生成 token
    |
    */

    "keys" => [

        /*
        |--------------------------------------------------------------------------
        | Public Key
        |--------------------------------------------------------------------------
        |
        | 公鑰
        |
        */

        "public" => env("JWT_PUBLIC_KEY"),

        /*
        |--------------------------------------------------------------------------
        | Private Key
        |--------------------------------------------------------------------------
        |
        | 私鑰
        |
        */

        "private" => env("JWT_PRIVATE_KEY"),

        /*
        |--------------------------------------------------------------------------
        | Passphrase
        |--------------------------------------------------------------------------
        |
        | 私鑰的密碼。 如果沒有設(shè)置,可以為 null。
        |
        */

        "passphrase" => env("JWT_PASSPHRASE"),

    ],

    /*
    |--------------------------------------------------------------------------
    | JWT time to live
    |--------------------------------------------------------------------------
    |
    | 指定 access_token 有效的時間長度(以分鐘為單位),默認(rèn)為1小時,您也可以將其設(shè)置為空,以產(chǎn)生永不過期的標(biāo)記
    |
    */

    "ttl" => env("JWT_TTL", 60),

    /*
    |--------------------------------------------------------------------------
    | Refresh time to live
    |--------------------------------------------------------------------------
    |
    | 指定 access_token 可刷新的時間長度(以分鐘為單位)。默認(rèn)的時間為 2 周。
    | 大概意思就是如果用戶有一個 access_token,那么他可以帶著他的 access_token 
    | 過來領(lǐng)取新的 access_token,直到 2 周的時間后,他便無法繼續(xù)刷新了,需要重新登錄。
    |
    */

    "refresh_ttl" => env("JWT_REFRESH_TTL", 20160),

    /*
    |--------------------------------------------------------------------------
    | JWT hashing algorithm
    |--------------------------------------------------------------------------
    |
    | 指定將用于對令牌進(jìn)行簽名的散列算法。
    |
    */

    "algo" => env("JWT_ALGO", "HS256"),

    /*
    |--------------------------------------------------------------------------
    | Required Claims
    |--------------------------------------------------------------------------
    |
    | 指定必須存在于任何令牌中的聲明。
    | 
    |
    */

    "required_claims" => [
        "iss",
        "iat",
        "exp",
        "nbf",
        "sub",
        "jti",
    ],

    /*
    |--------------------------------------------------------------------------
    | Persistent Claims
    |--------------------------------------------------------------------------
    |
    | 指定在刷新令牌時要保留的聲明密鑰。
    |
    */

    "persistent_claims" => [
        // "foo",
        // "bar",
    ],

    /*
    |--------------------------------------------------------------------------
    | Blacklist Enabled
    |--------------------------------------------------------------------------
    |
    | 為了使令牌無效,您必須啟用黑名單。
????| 如果您不想或不需要此功能,請將其設(shè)置為 false。
    |
    */

    "blacklist_enabled" => env("JWT_BLACKLIST_ENABLED", true),

    /*
    | -------------------------------------------------------------------------
    | Blacklist Grace Period
    | -------------------------------------------------------------------------
    |
    | 當(dāng)多個并發(fā)請求使用相同的JWT進(jìn)行時,
????| 由于 access_token 的刷新 ,其中一些可能會失敗
????| 以秒為單位設(shè)置請求時間以防止并發(fā)的請求失敗。
    |
    */

    "blacklist_grace_period" => env("JWT_BLACKLIST_GRACE_PERIOD", 0),

    /*
    |--------------------------------------------------------------------------
    | Providers
    |--------------------------------------------------------------------------
    |
    | 指定整個包中使用的各種提供程序。
    |
    */

    "providers" => [

        /*
        |--------------------------------------------------------------------------
        | JWT Provider
        |--------------------------------------------------------------------------
        |
        | 指定用于創(chuàng)建和解碼令牌的提供程序。
        |
        */

        "jwt" => TymonJWTAuthProvidersJWTNamshi::class,

        /*
        |--------------------------------------------------------------------------
        | Authentication Provider
        |--------------------------------------------------------------------------
        |
        | 指定用于對用戶進(jìn)行身份驗(yàn)證的提供程序。
        |
        */

        "auth" => TymonJWTAuthProvidersAuthIlluminate::class,

        /*
        |--------------------------------------------------------------------------
        | Storage Provider
        |--------------------------------------------------------------------------
        |
        | 指定用于在黑名單中存儲標(biāo)記的提供程序。
        |
        */

        "storage" => TymonJWTAuthProvidersStorageIlluminate::class,

    ],

];
自定義認(rèn)證中間件

先來說明一下我想要達(dá)成的效果,我希望用戶提供賬號密碼前來登錄。如果登錄成功,那么我會給前端頒發(fā)一個 access _token ,設(shè)置在 header 中以請求需要用戶認(rèn)證的路由。

同時我希望如果用戶的令牌如果過期了,可以暫時通過此次請求,并在此次請求中刷新該用戶的 access _token,最后在響應(yīng)頭中將新的 access _token 返回給前端,這樣子可以無痛的刷新 access _token ,用戶可以獲得一個很良好的體驗(yàn),所以開始動手寫代碼。

執(zhí)行如下命令以新建一個中間件:

php artisan make:middleware RefreshToken

中間件代碼如下:

RefreshToken.php

checkForToken($request);

       // 使用 try 包裹,以捕捉 token 過期所拋出的 TokenExpiredException  異常
        try {
            // 檢測用戶的登錄狀態(tài),如果正常則通過
            if ($this->auth->parseToken()->authenticate()) {
                return $next($request);
            }
            throw new UnauthorizedHttpException("jwt-auth", "未登錄");
        } catch (TokenExpiredException $exception) {
          // 此處捕獲到了 token 過期所拋出的 TokenExpiredException 異常,我們在這里需要做的是刷新該用戶的 token 并將它添加到響應(yīng)頭中
            try {
                // 刷新用戶的 token
                $token = $this->auth->refresh();
               // 使用一次性登錄以保證此次請求的成功
                Auth::guard("api")->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()["sub"]);
            } catch (JWTException $exception) {
               // 如果捕獲到此異常,即代表 refresh 也過期了,用戶無法刷新令牌,需要重新登錄。
                throw new UnauthorizedHttpException("jwt-auth", $exception->getMessage());
            }
        }
        
        // 在響應(yīng)頭中返回新的 token
        return $this->setAuthenticationHeader($next($request), $token);
    }
}
設(shè)置 Axios 攔截器

我選用的 HTTP 請求套件是 axios。為了達(dá)到無痛刷新 token 的效果,我們需要對 axios 定義一個攔截器,用以接收我們刷新的 Token,代碼如下:

app.js

import Vue from "vue"
import router from "./router"
import store from "./store"
import iView from "iview"
import "iview/dist/styles/iview.css"

Vue.use(iView)


new Vue({
    el: "#app",
    router,
    store,
    created() {
        // 自定義的 axios 響應(yīng)攔截器
        this.$axios.interceptors.response.use((response) => {
            // 判斷一下響應(yīng)中是否有 token,如果有就直接使用此 token 替換掉本地的 token。你可以根據(jù)你的業(yè)務(wù)需求自己編寫更新 token 的邏輯
            var token = response.headers.authorization
            if (token) {
                // 如果 header 中存在 token,那么觸發(fā) refreshToken 方法,替換本地的 token
                this.$store.dispatch("refreshToken", token)
            }
            return response
        }, (error) => {
            switch (error.response.status) {
                
                // 如果響應(yīng)中的 http code 為 401,那么則此用戶可能 token 失效了之類的,我會觸發(fā) logout 方法,清除本地的數(shù)據(jù)并將用戶重定向至登錄頁面
                case 401:
                    return this.$store.dispatch("logout")
                    break
                // 如果響應(yīng)中的 http code 為 400,那么就彈出一條錯誤提示給用戶
                case 400:
                    return this.$Message.error(error.response.data.error)
                    break
            }
            return Promise.reject(error)
        })
    }
})

Vuex 內(nèi)的代碼如下:

store/index.js

import Vue from "vue"
import Vuex from "vuex"
import axios from "axios"

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        name: null,
        avatar: null,
        mobile: null,
        token: null,
        remark: null,
        auth: false,
    },
    mutations: {
        // 用戶登錄成功,存儲 token 并設(shè)置 header 頭
        logined(state, token) {
            state.auth = true
            state.token = token
            localStorage.token = token
        },
        // 用戶刷新 token 成功,使用新的 token 替換掉本地的token
        refreshToken(state, token) {
            state.token = token
            localStorage.token = token
            axios.defaults.headers.common["Authorization"] = state.token
        },
        // 登錄成功后拉取用戶的信息存儲到本地
        profile(state, data) {
            state.name = data.name
            state.mobile = data.mobile
            state.avatar = data.avatar
            state.remark = data.remark
        },
        // 用戶登出,清除本地數(shù)據(jù)
        logout(state){
            state.name = null
            state.mobile = null
            state.avatar = null
            state.remark = null
            state.auth = false
            state.token = null

            localStorage.removeItem("token")
        }
    },
    actions: {
         // 登錄成功后保存用戶信息
        logined({dispatch,commit}, token) {
            return new Promise(function (resolve, reject) {
                commit("logined", token)
                axios.defaults.headers.common["Authorization"] = token
                dispatch("profile").then(() => {
                    resolve()
                }).catch(() => {
                    reject()
                })
            })
        },
        // 登錄成功后使用 token 拉取用戶的信息
        profile({commit}) {
            return new Promise(function (resolve, reject) {
                axios.get("profile", {}).then(respond => {
                    if (respond.status == 200) {
                        commit("profile", respond.data)
                        resolve()
                    } else {
                        reject()
                    }
                })
            })
        },
        // 用戶登出,清除本地數(shù)據(jù)并重定向至登錄頁面
        logout({commit}) {
            return new Promise(function (resolve, reject) {
                commit("logout")
                axios.post("auth/logout", {}).then(respond => {
                    Vue.$router.push({name:"login"})
                })
            })
        },
        // 將刷新的 token 保存至本地
        refreshToken({commit},token) {
            return new Promise(function (resolve, reject) {
                commit("refreshToken", token)
            })
        },
    }
})
更新異常處理的 Handler

由于我們構(gòu)建的是 api 服務(wù),所以我們需要更新一下 app/Exceptions/Handler.php 中的 render

方法,自定義處理一些異常。

Handler.php

 array_first(array_collapse($exception->errors()))], 400);
        }
        // 用戶認(rèn)證的異常,我們需要返回 401 的 http code 和錯誤信息
        if ($exception instanceof UnauthorizedHttpException) {
            return response($exception->getMessage(), 401);
        }

        return parent::render($request, $exception);
    }
}

更新完此方法后,我們上面自定義的中間件里拋出的異常和我們下面參數(shù)驗(yàn)證錯誤拋出的異常都會被轉(zhuǎn)為指定的格式拋出。

使用

現(xiàn)在,我們可以在我們的 routes/api.php 路由文件中新增幾條路由來測試一下了:

api.php

Route::prefix("auth")->group(function($router) {
    $router->post("login", "AuthController@login");
    $router->post("logout", "AuthController@logout");


});

Route::middleware("refresh.token")->group(function($router) {
    $router->get("profile","UserController@profile");
});

在你的 shell 中運(yùn)行如下命令以新增一個控制器:

$ php artisan make:controller AuthController

打開此控制器,寫入如下內(nèi)容

 [
                "required",
                "exists:users",
            ],
            "password" => "required|string|min:6|max:20",
         ];
          
        // 驗(yàn)證參數(shù),如果驗(yàn)證失敗,則會拋出 ValidationException 的異常
        $params = $this->validate($request, $rules);

       // 使用 Auth 登錄用戶,如果登錄成功,則返回 201 的 code 和 token,如果登錄失敗則返回
        return ($token = Auth::guard("api")->attempt($params))
            ? response(["token" => "bearer " . $token], 201)
            : response(["error" => "賬號或密碼錯誤"], 400);
    }

    /**
     * 處理用戶登出邏輯
     *
     * @return IlluminateHttpJsonResponse
     */
    public function logout()
    {
        Auth::guard("api")->logout();

        return response(["message" => "退出成功"]);
    }
}

然后我們進(jìn)入 tinker

$ php artisan tinker

執(zhí)行以下命令來創(chuàng)建一個測試用戶,我這里的用戶名是用的是手機(jī)號碼,你可以自行替換為郵箱。別忘了設(shè)置命名空間喲:

>>> namespace AppModels;
>>> User::create(["name" => "Test","mobile" => 17623239881,"password" => bcrypt("123456")]);

正確執(zhí)行結(jié)果如下圖:

然后打開 Postman 來進(jìn)行 api 測試

正確的請求結(jié)果如下圖:

可以看到我們已經(jīng)成功的拿到了 token,接下來我們就去驗(yàn)證一下刷新 token 吧

如圖可以看到我們已經(jīng)拿到了新的 token,接下來的事情便會交由我們前面設(shè)置的 axios 攔截器處理,它會將本地的 token 替換為此 token。

版本科普

感覺蠻多人對版本沒什么概念,所以在這里科普下常見的版本。

α(Alpha)版

? 這個版本表示該 Package 僅僅是一個初步完成品,通常只在開發(fā)者內(nèi)部交流,也有很少一部分發(fā)布給專業(yè)測試人員。一般而言,該版本軟件的 Bug 較多,普通用戶最好不要安裝。

β(Beta)版

該版本相對于 α(Alpha)版已有了很大的改進(jìn),修復(fù)了嚴(yán)重的錯誤,但還是存在著一些缺陷,需要經(jīng)過大規(guī)模的發(fā)布測試來進(jìn)一步消除。通過一些專業(yè)愛好者的測試,將結(jié)果反饋給開發(fā)者,開發(fā)者們再進(jìn)行有針對性的修改。該版本也不適合一般用戶安裝。

RC/ Preview版

RC 即 Release Candidate 的縮寫,作為一個固定術(shù)語,意味著最終版本準(zhǔn)備就緒。一般來說 RC 版本已經(jīng)完成全部功能并清除大部分的 BUG。一般到了這個階段 Package 的作者只會修復(fù) Bug,不會對軟件做任何大的更改。

普通發(fā)行版本

一般在經(jīng)歷了上面三個版本后,作者會推出此版本。此版本修復(fù)了絕大部分的 Bug,并且會維護(hù)一定的時間。(時間根據(jù)作者的意愿而決定,例如 Laravel 的一般發(fā)行版本會提供為期一年的維護(hù)支持。)

LTS(Long Term Support) 版

該版本是一個特殊的版本,和普通版本旨在支持比正常時間更長的時間。(例如 Laravel 的 LTS 版本會提供為期三年的 維護(hù)支持。)

結(jié)語

jwt-auth 確實(shí)是一個很棒的用戶認(rèn)證 Package,配置簡單,使用方便。

文章結(jié)束,感謝閱讀。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/26275.html

相關(guān)文章

  • PHP / Laravel API 開發(fā)推薦閱讀清單

    showImg(https://segmentfault.com/img/bV6aHV?w=1280&h=800); 社區(qū)優(yōu)秀文章 Laravel 5.5+passport 放棄 dingo 開發(fā) API 實(shí)戰(zhàn),讓 API 開發(fā)更省心 - 自造車輪。 API 文檔神器 Swagger 介紹及在 PHP 項(xiàng)目中使用 - API 文檔撰寫方案 推薦 Laravel API 項(xiàng)目必須使用的 8 個...

    shmily 評論0 收藏0
  • Laravel 5.5 使用 Passport 實(shí)現(xiàn) Auth 認(rèn)證

    摘要:最近在寫一個前后端分離項(xiàng)目,本來想用開發(fā)的,但是略感笨重,于是想到了的和新出的。更改看守器驅(qū)動將配置文件中授權(quán)看守器的的選項(xiàng)改為。然后在你的前端請求里需要加入一個參數(shù)然后在你需要使用到認(rèn)證的路由里使用中間件,一切就大功告成啦 最近在寫一個前后端分離項(xiàng)目,本來想用 Jwt-auth + Dingo 開發(fā)的,但是略感笨重,于是想到了 Laravel 的 Passport 和 5.5 新出的...

    miguel.jiang 評論0 收藏0
  • API 開發(fā)中可選擇傳遞 token 接口遇到的一個坑

    摘要:此處做刷新處理具體代碼可以參考必須需要登錄驗(yàn)證的接口在響應(yīng)頭中返回新的問題解決。 在做 API 開發(fā)時,不可避免會涉及到登錄驗(yàn)證,我使用的是jwt-auth 在登錄中會經(jīng)常遇到一個token過期的問題,在config/jwt.php默認(rèn)設(shè)置中,這個過期時間是一個小時,不過為了安全也可以設(shè)置更小一點(diǎn),我設(shè)置了為五分鐘。 五分鐘過期,如果就讓用戶去登錄,這種體驗(yàn)會讓用戶直接拋棄你的網(wǎng)站...

    siberiawolf 評論0 收藏0
  • laravel使用JWT做API認(rèn)證

    摘要:最近項(xiàng)目做認(rèn)證,最終技術(shù)選型決定使用,項(xiàng)目框架使用的是,使用有比較方便使用的開源包。使用安裝,使用的框架版本為,最新穩(wěn)定版本為。 最近項(xiàng)目做API認(rèn)證,最終技術(shù)選型決定使用JWT,項(xiàng)目框架使用的是laravel,laravel使用JWT有比較方便使用的開源包:jwt-auth。 使用composer安裝jwt-auth,laravel使用的框架版本為5.0,jwt-auth最新穩(wěn)定版本...

    SexySix 評論0 收藏0
  • Laravel Passport里的授權(quán)類型介紹

    摘要:模糊授權(quán),跟上面的認(rèn)證碼授權(quán)類似,不同的是,我們的資源服務(wù)器,返回的直接就是準(zhǔn)入令牌,而不是認(rèn)證碼。 本文來自pilishen.com----原文鏈接; 歡迎來和pilishen一起學(xué)習(xí)php&Laravel;學(xué)習(xí)群:109256050 OAuth2是一個安全框架,控制著程序受保護(hù)部分的準(zhǔn)入,主要是控制不同的客戶端如何來調(diào)取API,保證它們在請求相應(yīng)資源的時候有相應(yīng)的權(quán)限。 Larav...

    RobinTang 評論0 收藏0

發(fā)表評論

0條評論

xavier

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<