GAE中Go后端+Angular前端基于app.yaml路由的Session验证方案问询
问题:GAE上Go+Angular架构下如何实现未登录跳转至/login页面?
我正在构建部署在Google App Engine(GAE)上的应用,采用Go后端、Angular前端架构,要求用户未持有Session或Session中loggedIn≠1时,自动跳转至/login页面。
我原本尝试通过App Engine的app.yaml完成几乎所有路由配置,但遇到了瓶颈。我的目录结构如下:
/myapp/app.yaml/myapp/server/main.go/myapp/client/(ANGULAR)
当前使用的app.yaml配置如下:
application: myapp version: 1 runtime: go111 main: ./server - url: /go/.* #Anything that goes to the golang app script: _go_app # Routing for bundles to serve directly - url: /((?:inline|main|polyfills|styles|vendor)\.[a-z0-9]+\.bundle\.js) secure: always redirect_http_response_code: 301 static_files: client/app/dist/\1 upload: client/app/dist/.* # Routing for a prod styles.bundle.css to serve directly - url: /(styles\.[a-z0-9]+\.bundle\.css) secure: always redirect_http_response_code: 301 static_files: client/app/dist/\1 upload: client/app/dist/.* # Routing for typedoc, assets and favicon.ico to serve directly - url: /((?:assets|docs)/.*|favicon\.ico) secure: always redirect_http_response_code: 301 static_files: client/app/dist/\1 upload: client/app/dist/.* # Any other requests are routed to index.html for angular to handle so we don't need hash URLs - url: /.* redirect_http_response_code: 301 static_files: client/app/dist/index.html upload: client/app/dist/index\.html
目前的路由逻辑是:/go路径作为API处理CRUD操作,其余请求均直接路由至Angular。但我发现app.yaml无法检查Session状态,非/go路径没有服务器端逻辑可验证Session。请问这种路由方式下是否无法实现Session验证?是否必须改用Go路由来为每个请求添加Session检查?
回答
没错,你猜的很准——app.yaml确实没办法直接处理Session验证,它本质上只是一个静态路由规则配置文件,没有执行服务器端逻辑、读取/校验Session的能力。所以你必须调整路由策略,让Go后端接管所有需要权限校验的请求,具体可以这么做:
1. 修改app.yaml,让非静态资源请求先经过Go服务
保留静态资源(Angular的bundle、assets、css等)的直接路由(这些不需要权限校验),把原来直接指向index.html的路由改为转发到Go服务:
application: myapp version: 1 runtime: go111 main: ./server # 静态资源直接路由,无需校验 - url: /((?:inline|main|polyfills|styles|vendor)\.[a-z0-9]+\.bundle\.js) secure: always redirect_http_response_code: 301 static_files: client/app/dist/\1 upload: client/app/dist/.* - url: /(styles\.[a-z0-9]+\.bundle\.css) secure: always redirect_http_response_code: 301 static_files: client/app/dist/\1 upload: client/app/dist/.* - url: /((?:assets|docs)/.*|favicon\.ico) secure: always redirect_http_response_code: 301 static_files: client/app/dist/\1 upload: client/app/dist/.* # API请求直接走Go服务 - url: /go/.* script: _go_app # 所有其他请求(Angular路由)先交给Go服务处理权限校验 - url: /.* script: _go_app
2. 在Go后端添加Session校验中间件
在main.go里,编写一个中间件函数,用来检查用户的Session状态:
package main import ( "net/http" "strings" // 这里导入你用来处理Session的库,比如GAE的datastore或者第三方Session库 // "google.golang.org/appengine" // "github.com/gorilla/sessions" ) // sessionAuthMiddleware 校验Session的中间件 func sessionAuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 排除不需要校验的路径:比如/login页面、API路径 if strings.HasPrefix(r.URL.Path, "/login") || strings.HasPrefix(r.URL.Path, "/go/") { next.ServeHTTP(w, r) return } // 这里写你的Session校验逻辑 session, err := sessionStore.Get(r, "your-session-name") if err != nil || session.Values["loggedIn"] != 1 { // 未登录,跳转到/login页面 http.Redirect(w, r, "/login", http.StatusFound) return } // 已登录,继续处理请求 next.ServeHTTP(w, r) }) } // serveAngularIndex 用来返回Angular的index.html func serveAngularIndex(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "./client/app/dist/index.html") } func main() { // 注册路由 mux := http.NewServeMux() // API路由 mux.Handle("/go/", http.StripPrefix("/go/", yourAPIRouter)) // Angular路由的请求,返回index.html mux.HandleFunc("/", serveAngularIndex) // 把中间件应用到整个路由链 http.Handle("/", sessionAuthMiddleware(mux)) }
3. 关键注意事项
- Session存储:GAE上可以选择用
gorilla/sessions配合GAE的Datastore或Memcache来存储Session,确保Session可以跨实例共享。 - Angular路由兼容:因为所有Angular的路由请求都会先经过Go服务,所以Go服务需要把这些请求转发到
index.html,让Angular的路由系统接管,这就是serveAngularIndex函数的作用。 - /login页面的特殊处理:一定要在中间件里排除
/login路径的校验,否则会出现无限跳转的问题。
这种方案的好处是把所有权限校验逻辑集中在Go后端,逻辑统一且易于维护,完全符合GAE的架构模式。
内容的提问来源于stack exchange,提问作者Chemdream
相关产品推荐
相关产品推荐

