gorilla 웹 툴킷이라는 Go의 서드파티 라이브러리가 있습니다. 그 중에 session 이라는 패키지는 쿠키, 세션등을 편리하게 이용할 수 있는 기능을 제공합니다. 이 글에는 session 패키지를 이용해서 사용자 정보를 쿠키에 저장하다가 알게 된 것을 기록해 두려고 합니다.
구현하려던 기능은 이렇습니다.
- 사용자가 접속하면 로그인 정보를 확인합니다.
- 로그인 되지 않은 경우, 로그인을 요청합니다.
- 로그인 후 사용자 정보를 쿠키에 저장합니다.
- 일정 시간동안은 브라우져를 종료하더라도 쿠키에서 사용자 정보를 읽어 로그인하지 않도록 합니다.
그렇게 하기위해 다음과 같은 사용자 정보를 보관할 구조체를 선언합니다.
type User struct {
Name string
Email string
}
그리고 main.html을 보여줄 MainHandler는 쿠키에 사용자 정보가 있는지 확인하고, 없는 경우, 로그인을 하도록 합니다.
func MainHandler(w http.ResponseWriter, r *http.Request){
session, _ := store.Get(r, "session")
userInfo := session.Values["user"]
if userInfo == nil {
http.Redirect(w, r, "/login", http.StatusFound)
}else{
tmpl, _ := template.ParseFiles("main.html")
tmpl.Execute(w, userInfo)
}
}
마지막으로 로그인핸들러에서 로그인이 완료된 사용자의 정보를 쿠키에 저장합니다.
func LoginHandler(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session")
session.Options = &sessions.Options{
Path: "/",
MaxAge: 60 * 60,
}
userInfo := User{
Name: r.FormValue("name"),
Email: r.FormValue("email"),
}
session.Values["state"] = userInfo
session.Save(r, w)
}
이렇게 한 후, 로그인을 해봤는데, LoginHandler에서 아무리 저장해도 MainHandler에서는 사용자 정보를 읽어오지 못했습니다. 물로 에러도 발생하지 았았구요. 한참을 헤매다 혹시 저장이 되지 않는 것은 아닐까 싶어서 살펴본 "session.Save(r, w)" 에서 리턴이 있는 것을 발견하고 에러를 한번 출력해봤습니다.
LoginHandler를 다음과 같이 수정했습니다.
func loginHandler(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session")
session.Options = &sessions.Options{
Path: "/",
MaxAge: 60 * 60,
}
userInfo := User{
Name: r.FormValue("name"),
Email: r.FormValue("email"),
}
session.Values["state"] = userInfo
err := session.Save(r, w)
if err != nil {
log.Println("error occurred : ", err )
}
}
그렇게 하고 실행했더니... 역시나 에러가 발생하고 있었습니다.
securecookie: error - caused by: securecookie: error - caused by: gob: type not registered for interface: main.User
User구조체를 바로 쿠키에 저장할때 문제가 되었던 모양입니다. (Go에서 에러를 처리하는 방식이 다르다는 것을 한번 더 실감 합니다. ) 이를 해결하기 위해서 main함수에 User구조체를 gob 인코딩을 할 수 있도록 "gob.Register(User{})" 코드를 추가합니다.
func main() {
gob.Register(User{})
http.HandleFunc("/", MainHandler)
http.HandleFunc("/login", LoginView)
http.HandleFunc("/dologin", LoginHandler)
log.Fatal(http.ListenAndServe(":8000", nil))
}
이제는 User구조체는 gob로 인식되어 세션에 저장과 불러오기 정상적으로 동작하게 되었습니다.
session 패키지를 이용해 쿠키에 저장할 수 있는 것은 기본적으로 string이고, 객체를 저장하려면 gob로 등록하여야 한다는 것을 알았습니다. 알고보면 어렵지는 않은데, 이전에 많이 사용하던 Rails에 익숙해지다보니, Rails에서는 당연하게 되던 것이 Go에서는 그렇지 않은 경우가 많아 시간을 허비하는 경우가 종종 생기는 것같습니다. 그리고 Go에서는 Exception이 없으니, 에러처리를 반드시 하는 것도 좀 당혹스럽게 만드는 점이고, 에러처리하는 코드를 꼭 만드는 습관을 가져야겠습니다.