์ฟ ํค๊ฐ ๋ฐ๊ธ๋์ง ์์ ๋
KOS ํ๋ก์ ํธ๋ ํ๋ก ํธ์๋์ React.js๋ฅผ ์ฌ์ฉํ๊ณ ์๋ฒ๋ go lang ๋ผ์ด๋ธ๋ฌ๋ฆฌ gin์ ์ด์ฉํ์ฌ ์งํ์ค์ด๋ค. ์ฒ์์ api๋ฅผ ๋ง๋ค๊ณ ๋์๋ postman์ด๋ผ๋ ํด๋ก ์ ๋๋ก ๋์ํ๋์ง ๊ฒ์ฌํ๋ค. ์ฒ์์๋ api์ฐ๊ฒฐ์ด ์์กฐ๋กญ๊ฒ ๋๋ค๊ฐ ๋ก๊ทธ์ธ์ ์ํด์ ์ฟ ํค๋ฅผ ๋ฐ๊ธํ๋ api๋ฅผ ์์ฑํ ์ดํ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
์ฟ ํค๊ฐ ๋ฐ๊ธ๋์ง ์๋๋ค.
ํ๋ก ํธ์๋์์ ๋ฐ์ Network๋ 200์ผ๋ก ์ ์์ด๊ณ set-cookie๋๋ ๊ฒ๊น์ง ๋ณด์ด๋ฉฐ response๋ฅผ ์ถ๋ ฅํด๋ณด์๋ ์ ์์ด๋ค. ๊ทธ๋ ๋ค๋ฉด ์ ์ฟ ํค๊ฐ ๋ฐ๊ธ๋์ง ์์๊น?
๋ฐฑ์๋์์ ํ๋ก ํธ์๋์ ์ฟ ํค๋ฅผ ์ ์ฅ์ํค๊ธฐ ์ํด์๋ ์์ชฝ์ credential ์์ฑ์ ๋ชจ๋ ON ํด์ฃผ์ด์ผํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋จผ์ ๋ฐฑ์๋(go lang)์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
// router
import {
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
}
r := gin.Default()
config := cors.DefaultConfig()
config.AllowOrigins = []string{"http://localhost:3000", "http://127.0.0.1:3000"} // origin ํ์ฉ
config.AllowCredentials = true // credential ํ์ฉ
r.Use(cors.New(config))
// Controller
c.SetCookie("access-token", signed, 60*60, "/", "", false, true)
router ๋จ์์ config๋ก ํ์ฉํ๋ origin์ ํ๋ก ํธ์๋์ origin์ ์ถ๊ฐํด์ค๋ค. ๋ํ AllowCredential๋ true๋ก ๋ณ๊ฒฝํ์ฌ ํ์ฉํด์ค๋ค.
์ฌ๊ธฐ์ AllowOrigins๋ฅผ *(์์ผ๋์นด๋)๋ก ์ฒ๋ฆฌํ๋ฉด ์๋๋๋ฐ ์ด์ ๋ [์ฃผ์ํ ์ ](#์ฃผ์ํ ์ )์ ๊ธฐ์ฌ๋์ด์๋ค.
Controller์์ ์ฟ ํค๋ฅผ ๋ฐ๊ธํ๋ ์ฝ๋๋ *gin.Context ๊ฐ์ฒด์ธ c์ SetCookie๋ฅผ ์ด์ฉํ์๋ค.
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)
์ถ์ฒ : https://pkg.go.dev/github.com/gin-gonic/gin
httpOnly ์์ฑ์ true๋ก ํด์ฃผ์ด์ผ ์ ์ ๊ฐ ์ฟ ํค๋ฅผ ์ง์ ์์ ํ ์ ์๋ค.
๊ทธ๋๋ ์ฟ ํค๊ฐ ๋ฐ๊ธ๋์ง ์๋ ์ด์ ๋ ํ๋ก ํธ์๋ ๋จ์์๋ credential์ ONํด์ฃผ์ด์ผํ๊ธฐ ๋๋ฌธ์ด๋ค.
const login = () => {
// ๋ก๊ทธ์ธ
axios.post('http://localhost:8080/v1/user-api/login', {
ID: 'heejin',
Password: '1234'
}, { withCredentials: true }) // withCredential ์ต์
ON
.then((res) => {
// ํ ํฐ ๋ฐ๊ธ๋จ
console.dir(res);
window.location.href = `${window.origin}/home`; // home์ผ๋ก redirect
})
.catch((e) => {
console.dir(e);
});
};
axios์์ ์ ๊ณตํ๋ withCredentials ์ต์ ์ true๋ก ์ค์ ํ๋, ๋ฐฑ์๋ ์ฝ๋์์ setCookie๋ฅผ ์ ์์ ์ผ๋ก ์คํํ ์ ์๊ฒ ๋์๊ณ ํ ํฐ์ด ์ ์์ ์ผ๋ก ์ ์ฅ๋์๋ค.
axios ์ฌ์ดํธ๋ฅผ ๋ณด๋ฉด ๊ธฐ๋ณธ ๊ฐ์ผ๋ก withCredentials ์์ฑ์ด false๋ก ๋์ด์์์ ํ์ธํ ์ ์๋ค. ๋ฐ๋ผ์ ์ง์ true๋ก ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ค.
// `withCredentials`๋ ์๊ฒฉ ์ฆ๋ช
(credentials)์ ์ฌ์ฉํ์ฌ
// ํฌ๋ก์ค ์ฌ์ดํธ ์ ๊ทผ ์ ์ด(cross-site Access-Control) ์์ฒญ์ด ํ์ํ ๊ฒฝ์ฐ ์ค์ ํฉ๋๋ค.
withCredentials: false, // ๊ธฐ๋ณธ ๊ฐ
์ด๋ MDN Web Docs์ฌ์ดํธ๋ฅผ ์ฐธ์กฐํด๋ณด๋ฉด XMLHttpRequest
๊ฐ์ฒด์ withCredentials ๊ธฐ๋ฅ์ ๊ทธ๋๋ก ์ด์ฉํ ๊ฒ์ผ๋ก ๋ณผ ์ ์๋ค. ์ด ๊ธฐ๋ฅ์ boolean ๊ฐ์ผ๋ก ์ธํ
๋์ด cookie์ tls ์ธ์ฆ์์ ๊ฐ์ ์ธ์ฆ ์์๋ฅผ ์๋ฒ์์ ์ค์ ํ ์ ์๋์ง๋ฅผ ๊ฒฐ์ ํ๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก, ํ๋ก ํธ์๋ ์ฝ๋์ credential ์ต์ ๊ณผ ์๋ฒ์ credential ์ต์ ์ ๋ชจ๋ ON ํด์ฃผ๋ฉด ์ฟ ํค๋ฅผ setting ํ ์ ์๋ค.
์ฃผ์ํ ์
๊ทธ๋ผ์๋ ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋จ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
XMLHttpRequest cannot load http://localhost:8080/v1/user-api/login. The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:3000' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
ํด์ํด๋ณด๋ฉด ์๋ฒ์์ credential์ true๋ก ํ ๊ฑฐ๋ฉด, ๋ฐ๋ allow-origin์ ์์ผ๋์นด๋์ธ *๋ก ์ธํ ํ์ง ๋ง๊ณ ์ง์ ์ธํ ํ๋ผ๋ ๊ฒ์ด๋ค. ์๊ฐํด๋ณด๋ฉด ๋น์ฐํ ์๊ธฐ์ด๋ค. AllowOrigins๊ฐ *๋ก ์ธํ ๋์ด์์ผ๋ฉด ์๋ฒ์ credential์ true๋ก ํ์ฌ ์์ฒญํ ๋ชจ๋ ์ฌ์ดํธ์ credential์ ์ ๋ณด๋ฅผ ์๋ฒ๊ฐ ๋ง๋๋ก ๋ฐ๊ฟ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
config.AllowOrigins = []string{"http://localhost:3000", "http://127.0.0.1:3000"} // origin ํ์ฉ
๋ฐ๋ผ์ ์์ ์ฝ๋์ ๊ฐ์ด origin๋ ์ ํํด์ฃผ๋ฉด ์ ๋๋ก ๋์ํ๋ค.
์์์ ๊ณ์ ์ธ๊ธ๋ same site, cross-site์ ๋ํด์ ๊ถ๊ธํ๋ค๋ฉด ๋ค์ ํฌ์คํ ์ ์ฐธ์กฐ!
axios๋ fetch, XMLhttpRequest์ ๋ํด ๊ถ๊ธํ๋ค๋ฉด ๋ค์ ํฌ์คํ ์ ์ฐธ์กฐ!
Comment