Laravel / Vue Passport (SPA) – 将令牌存储到Cookie中

huangapple go评论65阅读模式
英文:

Laravel / Vue Passport (SPA) - Store token to cookies

问题

我一直在跟踪一个关于Vue + Laravel身份验证的教程,一切都已经设置好了,但是然后教程提到了将令牌存储在本地存储中。我已经阅读到这不是最佳实践,因为它更容易受到XSS攻击的影响。

问题在于很难找到关于将令牌存储在Cookie中的教程(特别是Laravel + Vue)。是否有人可以帮助我如何实现将令牌存储在Cookie中?

非常感谢任何能提供帮助的人。

以下是我的当前代码。

Controller(控制器)

public function login(Request $request) 
{
    $http = new \GuzzleHttp\Client;

    try {
        $response = $http->post(config('services.passport.login_endpoint'), [
            'form_params' => [
                'grant_type' => 'password',
                'client_id' => config('services.passport.client_id'),
                'client_secret' => config('services.passport.client_secret'),
                'username' => $request->username,
                'password' => $request->password,
            ]
        ]);
        return $response->getBody();
    } catch (\GuzzleHttp\Exception\BadResponseException $e) {
        if ($e->getCode() === 400) {
            return response()->json('Invalid Request. Please enter a username or a password.', $e->getCode());
        } else if ($e->getCode() === 401) {
            return response()->json('Your credentials are incorrect. Please try again', $e->getCode());
        }
        return response()->json('Something went wrong on the server.', $e->getCode());
    }
}

public function logout()
{
    auth()->user()->tokens->each(function ($token, $key) {
        $token->delete();
    });
    
    return response()->json('Logged out successfully', 200);
}

API 路由(路由)

Route::post('/login', 'AuthController@login');
Route::middleware('auth:api')->post('/logout', 'AuthController@logout');

Vue 组件脚本

<script>
export default {
  props: {
    source: String,
  },
  data: () => ({
    username: '',
    password: '',
    valid: false,
  }),

  methods: {
    save() {
      const { username, password } = this;
      axios
        .post('api/login', { username, password })
        .then(response => console.log(response))
        .catch(error => console.log(error));
    }
  }
}
</script>

希望这可以帮助你。

英文:

I have been following a tutorial about Vue + Laravel authentication and everything is set-up but then the tutorial went to storing tokens in a local storage. I have read that this is not the best practice that should be followed since it is more susceptible to an XSS attack.

The problem is that it is very hard to find a tutorial about storing tokens in a cookie (specifically Laravel + Vue). Can anyone please help on how to implement storing tokens in a cookie?

Thank you very much for anyone who could help.

Here is my current code.

Controller

public function login(Request $request) 
{
	$http = new\GuzzleHttp\Client;

	try {
		$response = $http-&gt;post(config(&#39;services.passport.login_endpoint&#39;), [
			&#39;form_params&#39; =&gt; [
				&#39;grant_type&#39; =&gt; &#39;password&#39;,
				&#39;client_id&#39; =&gt; config(&#39;services.passport.client_id&#39;),
				&#39;client_secret&#39; =&gt; config(&#39;services.passport.client_secret&#39;),
				&#39;username&#39; =&gt; $request-&gt;username,
				&#39;password&#39; =&gt; $request-&gt;password,
			]
		]);
		return $response-&gt;getBody();
	} catch (\GuzzleHttp\Exception\BadResponseException $e) {
		if ($e-&gt;getCode() === 400) {
		return response()-&gt;json(&#39;Invalid Request. Please enter a username or a password.&#39;, $e-&gt;getCode());
	} else if ($e-&gt;getCode() === 401) {
		return response()-&gt;json(&#39;Your credentials are incorrect. Please try again&#39;, $e-&gt;getCode());
	}
		return response()-&gt;json(&#39;Something went wrong on the server.&#39;, $e-&gt;getCode());
	}
}

public function logout()
{
	auth()-&gt;user()-&gt;tokens-&gt;each(function ($token, $key) {
		$token-&gt;delete();
	});
	
	return response()-&gt;json(&#39;Logged out successfully&#39;, 200);
}

API routes

Route::post(&#39;/login&#39;, &#39;AuthController@login&#39;);
Route::middleware(&#39;auth:api&#39;)-&gt;post(&#39;/logout&#39;, &#39;AuthController@logout&#39;);

Vue Component Script

&lt;script&gt;
  export default {
    props: {
      source: String,
    },
    data: () =&gt; ({
      username: &#39;&#39;,
      password: &#39;&#39;,
      valid: false,
    }),

    methods: {
      save() {
        const { username, password } = this
        axios 
        .post(&#39;api/login&#39;, { username, password })
        .then(response =&gt; console.log(response))
        .catch(error =&gt; console.log(error))
      }
    }
  }
&lt;/script&gt;

答案1

得分: 6

使用以下代码将令牌存储在 cookie 中:

&lt;script&gt;
  export default {
    props: {
      source: String,
    },
    data: () =&gt; ({
      username: &#39;&#39;,
      password: &#39;&#39;,
      valid: false,
    }),

    methods: {
      save() {
        const { username, password } = this
        axios 
        .post(&#39;api/login&#39;, { username, password })
        .then(response =&gt; {
           document.cookie =  response.data.token
        })
        .catch(error =&gt; console.log(error))
      }
    }
  }
&lt;/script&gt;

要获取 cookie 中的令牌,请使用以下 JavaScript 代码:

var token = document.cookie;

有关更多有关 cookie 的信息,可以查看这个链接

英文:

Use document.cookie = response.data.token to store token in cookie

&lt;script&gt;
  export default {
    props: {
      source: String,
    },
    data: () =&gt; ({
      username: &#39;&#39;,
      password: &#39;&#39;,
      valid: false,
    }),

    methods: {
      save() {
        const { username, password } = this
        axios 
        .post(&#39;api/login&#39;, { username, password })
        .then(response =&gt; {
           document.cookie =  response.data.token
             })
        .catch(error =&gt; console.log(error))
      }
    }
  }
&lt;/script&gt;

https://www.w3schools.com/js/js_cookies.asp

to get cookie

var token = document.cookie;

答案2

得分: 3

我认为最佳选择是将refresh_token(带有用户数据)用作服务器端cookie,并将token保存在Vue存储中(从token中需要的一切是用户视图的用户数据)。这个解决方案可以防止XSS攻击。这意味着服务器端的cookie会阻止JavaScript读取或写入该cookie。并且在每次重新加载页面时,您需要使用带有refresh_token cookie的'autoLogin'请求进行重新授权(每个请求都会自动使用cookie),例如:

Vue存储示例,如'auth.ts'或'auth.js':

/**
 * Autologin user.
 *
 * @param commit
 */
async autologin({ commit }: any) {
    try {
        let { data } = await axios.post(`${endpoint}/${silentLogin}`)
        setExpiresDateToken(data.accessToken)

        commit('auth', {
            token: data.accessToken,
            idToken: data.idToken,
        })
    } catch (err) {
        localStorage.removeItem('expires')
        throw err
    }
},

router.ts或router.js(我使用TypeScript):

/**
 * Check if user access allows.
 * @param to
 * @param from
 * @param next
 * @returns {Promise<void>}
 */
const authGuard = async (to: any, from: any, next: any) => {
    if (!store.getters['auth/isAuth']) {
        try {
            await store.dispatch('auth/autologin')
            next()
        } catch (e) {
            next({ name: 'login' })
        }
    } else {
        next()
    }
}

const routes = [
  {
    path: '/list',
    name: 'List',
    component: () => import('@/views/DocumentsList'),
    beforeEnter: authGuard,
  }
]

如果您使用Laravel路由器,可能有类似的方式。

英文:

I think the best option is to use refresh_token (with user data) as a server-side cookie. And save token in vue store (everything that you need from token is user data for user view). This solution makes an impossible XSS attack. This means server-side cookie block javascript to read or write this cookie. And every reloads pages you need to use 'autoLogin' request with refresh_token cookie for reauthorization (every request use automatically cookie) e.g.:

vue store e.g. 'auth.ts' or 'auth.js'

        /**
		 * Autologin user.
		 *
		 * @param commit
		 */
		async autologin({ commit }: any) {
			try {
				let { data } = await axios.post(`${endpoint}/${silentLogin}`)
				setExpiresDateToken(data.accessToken)

				commit(&#39;auth&#39;, {
					token: data.accessToken,
					idToken: data.idToken,
				})
			} catch (err) {
				localStorage.removeItem(&#39;expires&#39;)
				throw err
			}
		},

router.ts or router.js (I user TypeScript)

/**
 * Check if user access allows.
 * @param to
 * @param from
 * @param next
 * @returns {Promise&lt;void&gt;}
 */
const authGuard = async (to: any, from: any, next: any) =&gt; {
	if (!store.getters[&#39;auth/isAuth&#39;]) {
		try {
			await store.dispatch(&#39;auth/autologin&#39;)
			next()
		} catch (e) {
			next({ name: &#39;login&#39; })
		}
	} else {
		next()
	}
}

const routes = [
  {
	path: &#39;/list&#39;,
	name: &#39;List&#39;,
	component: () =&gt; import(&#39;@/views/DocumentsList&#39;),
	beforeEnter: authGuard,
  }
]

If you use Laravel routers it mas be a similar way

huangapple
  • 本文由 发表于 2020年1月3日 18:37:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/59577057.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定