鉴权
一 什么是鉴权
在网站中,有些页面是登录后的用户才能访问的,由于http是无状态的协议,我们无法确认用户的状态(如是否登录)。这时候浏览器在访问这些页面时,需要额外传输一些用户的账户信息给后台,让后台知道该用户是否登录、是哪个用户在访问。
二 cookie
cookie是浏览器实现的技术,在浏览器中可以存储用户是否登录的凭证,每次请求都会将该凭证发送给服务器。
cookie实现鉴权步骤:
- 用户登录成功后,后端向浏览器设置一个cookie:username=lisi
- 每次请求,浏览器会自动把该cookie发送给服务端
- 服务端处理请求时,从cookie中取出username,就知道是哪个用户了
- 如果没过期,则鉴权通过,过期了,则重定向到登录页
Go中使用Cookie:
// 登录时设置cookie
expiration := time.Now()
expiration = expiration.AddDate(1, 0, 0)
cookie := http.Cookie{Name: "username", Value: "张三", Expires: expiration}
http.SetCookie(w, &cookie)
// 再次访问时,获取浏览器传递的cookie
// 获取cookie方式一
username, _ := r.Cookie("username")
// 获取cookie方式二
for _, cookie := range r.Cookies() {
fmt.Println(cookie.Username)
}
但是这样做,风险很大,黑客很容易知道cookie中传递的内容,即用户的真实账户信息。
二 session
2.1 session原理
为了解决cookie的安全问题,基于cookie,衍生了session技术。session技术将用户的信息存储在了服务端,保证了安全,其实现步骤为:
- 服务端设置cookie时,不再存储username,而是存储一个随机生成的字符串,比如32位的uuid,服务端额外存储一个uuid与用户名的映射
- 用户再次请求时,会自动把cookie中的uuid带入给服务器
- 服务器使用uuid进行鉴权
一般上述的uuid在cookie中存储的键都是sid(session_id) ,也就是常说的session方案,服务端此时需要额外开辟空间存储sid与用户真实信息的对应映射。
2.2 session实现
如果要手动实现session,需要注意以下方面:
- 全局session管理器:
- 保证sessionid 的全局唯一性
- 为每个客户关联一个session
- session 过期处理
- session 的存储(可以存储到内存、文件、数据库等)
关于session数据(sid与真实用户的映射)的存储,可以存放在服务端的一个文件中,比如该session第三方库:https://github.com/gorilla/sessions
使用示例:
package main
import(
"fmt"
"net/http"
"github.com/gorilla/sessions"
)
// 利用cookie方式创建session,秘钥为 mykey
var store = sessions.NewCookieStore([]byte("mykey"))
func setSession(w http.ResponseWriter, r *http.Request){
session, _ := store.Get(r, "sid")
session.Values["username"] = "张三"
session.Save(r, w)
}
func profile(w http.ResponseWriter, r *http.Request){
session, _ := store.Get(r, "sid")
if session.Values["username"] == nil {
fmt.Fprintf(w, `未登录,请前往 localhost:8080/setSession`)
return
}
fmt.Fprintf(w, `已登录,用户是:%s`, session.Values["username"])
return
}
func main() {
// 访问隐私页面
http.HandleFunc("/profile", profile)
// 设置session
http.HandleFunc("/setSession", setSession)
server := http.Server{
Addr: ":8080",
}
server.ListenAndServe()
}
在企业级开发中,经常使用额外的数据库redis来存储session数据。
2.3 禁用cookie时候session方案
以上方式中,生成的sid都存储在cookie中,如果用户禁用了cookie,则每次请求服务端无法收到sid!我们需要想别的办法来让浏览器的每次请求都携带上sid,常用方式是URL重写:在返回给用户的页面里的所有的URL后面追加session标识符,这样用户在收到响应之后,无论点击响应页面里的哪个链接或提交表单,都会自动带上session标识符,从而就实现了会话的保持。