I'm trying to build an app that is a Go backend, Angular front end, hosted on Google App Engine, that forces you to /login if you don't have a session or if your session's loggedIn != 1.
I'm also trying to use the App Engine's app.yaml routing for almost everything.
I'm not sure this is possible?
Directory structure:
/myapp/app.yaml
/myapp/server/main.go
/myapp/client/(ANGULAR)
app.yaml (taken from: here ) application: myapp version: 1 runtime: go111 #api_version: go1 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: /.*
#secure: always
redirect_http_response_code: 301
static_files: client/app/dist/index.html
upload: client/app/dist/index\.html
#http_headers:
# Strict-Transport-Security: max-age=31536000; includeSubDomains
# X-Frame-Options: DENY
So, routes to /go would act as the api... CRUD stuff. Everything else would go to Angular.
So how could i have it check if there's a session? I doubt that's possible in the app.yaml. If a call is made NOT to /go, there's no real server to tell it if there's a session.
So, is it just not possible for me to do it this way? Would I be required to use Go's routing, so that, each call can have a session check?
Yes, you guess it correctly. Files / folders marked as static are served separately from your Go app (using Google's content delivery network), and as such, cannot be aware of your Go app's session IDs and states.
Is it a problem for you? Usually static files (e.g. HTML, CSS and JavaScript files) can be delivered without authorization / authentication, they don't pose a security risk.
If you don't want to make your static files "public", you have to use your Go app to serve them. Don't mark them as static, and use any of the file serving mechanism of Go's standard lib (e.g. http.FileServer()
, http.ServeFile()
or http.ServeContent()
). Use the middleware pattern to check for the existence of a session, and if one exists, only then call the file server.
(Or implement serving static content your it on your own, and you can do whatever you want / need to in your own handlers.)
For example to serve "protected" files from Go mapped to /protected
, and to have some "real" static files (served by Google automatically) mapped to /static
, it could look like this:
app.yaml
:
- url: /protected/.*
script: _go_app
- url: /static
static_dir: static
Then in your Go source you may serve the "protected" files like this:
func init() {
fileHandler := http.StripPrefix("/protected",
http.FileServer(http.Dir("protected")))
http.HandleFunc("/protected/", func(w http.ResponseWriter, r *http.Request) {
// You may check if a session exists here
sessExists := ...
if !sessExists {
http.Error(w, "you must login first", http.StatusUnauthorized)
return
}
// Serve the requested file:
fileHandler.ServeHTTP(w, r)
})
}
The above init()
function registers a handler that handles paths prefixed with /protected/
, and if a session exists (that logic belongs to you), it calls a file server that serves the content of the protected
folder. The file served is derived from the path, the /protected
prefix stripped. E.g. the path /protected/secret.txt
will designate the protected/secret.txt
file.