개요
- 로그인 시 발급되는 access token을 쿠키에 세팅
- 미들웨어에서 쿠키의 access token 을 검증
Cookie 세팅
func Login(res http.ResponseWriter, req *http.Request) {
accessTokenCookie := http.Cookie{
Name: "accessToken",
Value: accessToken,
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteNoneMode,
}
refreshTokenCookie := http.Cookie{
Name: "refreshToken",
Value: refreshToken,
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteNoneMode,
}
http.SetCookie(res, &accessTokenCookie)
http.SetCookie(res, &refreshTokenCookie)
}
검증 미들웨어
- 쿠키에서 토큰을 추출해서 컨텍스트에 담는다
- 담은 컨텍스트의 정보를 컨트롤러에서 사용한다.
type contextKey string
const (
userContextKey = contextKey("user")
)
type User struct {
UserId string
UserEmail string
UserStatus string
}
var excludeRouteList = []string{
"/", "/api",
"/user/signup", "/user/login",
}
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
for _, route := range excludeRouteList {
if r.URL.Path == route {
log.Printf("Found Match Route: %s", route)
next.ServeHTTP(w, r)
return
}
}
cookie, err := r.Cookie("accessToken")
log.Printf("Cookie: %s", cookie)
if err != nil {
log.Printf("Get Cookie Error :%v", err)
if err == http.ErrNoCookie {
response.Response(w, response.CommonResponseWithMessage{
Status: http.StatusUnauthorized,
Code: "AUTH001",
Message: "No access token provided",
})
return
}
response.Response(w, response.CommonResponseWithMessage{
Status: http.StatusUnauthorized,
Code: "AUTH002",
Message: "Invalid cookie format",
})
return
}
accessToken := cookie.Value
userId, userEmail, userStatus, validateErr := auth.ValidateJwtTokenFromString(accessToken)
if validateErr != nil {
log.Printf("ValidateErr Cookie Error :%v", validateErr)
if strings.Contains(validateErr.Error(), "token expired") {
response.Response(w, response.CommonResponseWithMessage{
Status: http.StatusUnauthorized,
Code: "AUTH003",
Message: "Token expired",
})
return
}
response.Response(w, response.CommonResponseWithMessage{
Status: http.StatusUnauthorized,
Code: "AUTH004",
Message: "Invalid token",
})
return
}
user := User{
UserId: userId,
UserEmail: userEmail,
UserStatus: userStatus,
}
ctx := context.WithValue(r.Context(), userContextKey, user)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func GetUserFromContext(ctx context.Context) (User, bool) {
user, ok := ctx.Value(userContextKey).(User)
return user, ok
}
컨트롤러에서 추출된 정보들 사용
func SampleController(res http.ResponseWriter, req *http.Request) {
user, ok := middlewares.GetUserFromContext(req.Context())
if !ok {
dto.SetErrorResponse(res, 401, "01", "JWT Verifying Error", nil)
return
}
dto.SetResponse(res, 200, "01")
}