My JWT validation now works on a microservice. How to I throw proper HTTP responses back?

xuanbao · 2018-01-10 02:30:10 · 691 次点击    
这是一个分享于 2018-01-10 02:30:10 的资源,其中的信息可能已经有所发展或是发生改变。

More namely, I need to throw a HTTP 403 back if the JWT verification anything but succeeds. How would you default to that?

The JWT verification works now. Here's my handler.

func (ma *myapp) SomeHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")

    reqToken := r.Header.Get("Authorization")
    splitToken := strings.Split(reqToken, "Bearer ")
    reqToken = splitToken[1] // It will crap out here, if there isn't an authorization header present

    err := lib.VerifyIDToken(ma.fbapp, reqToken)
    if err != nil {
        http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
        return
    }

    enc := json.NewEncoder(w)
    enc.Encode(lib.MarketDataMap)
}

However, if you just go to the URL itself, it will throw a 502 bad gateway from nginx, because my Go app throws an index out of bounds error for reqToken = splitToken[1], which makes sense since nothing is there.

How would one default to http 403 in a handler, in best practice? I can't attach err to the logic, before I am at VerifyIDToken, and there, the index out of bounds has already happened.

Any input is appreciated! I'm rather new to Go, but finding it nicer and nicer the more I learn :smile: Definitely gonna be my Go...-to language from now on(Coming from Java)


评论:

seankhliao:

if you need to do this for a lot of handlers you can wrap it in something like:

type precheck func(w http.ResponseWriter, r *http.Request)
func (p precheck) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        // verification here
        p(w, r)
}

and use it like this:

http.Handle('/some/path/', precheck(someHandler))
titpetric:

You can check len(splitToken) to see if you have 2 items.

if len(splitToken) < 2 {
    http.Error(...)
    return
}
reqToken = splitToken[1]
...
cbll:

But, since this service only responds to valid requests with an authentication header + JWT, wouldn't it be "prettier" for it to return 403 for everything except successful requests? Or maybe I'm just dreaming :)

titpetric:

Short answer: If you'd mask all bad requests to 403, you'll have a hard time tracking down the actual error. The 503 is a valid response, which you resolve by writing better code in this case. In another case it might indicate a database failure, or something else. Either way, it's something that should be investigated and corrected, and not hidden under the carpet ;)

Redundancy_:

a panic due to looking at a slice index that doesn't exist isn't pretty...

Alternatively, use empty values:

authorizationHeader := r.Header.Get("Authorization")
var reqToken string
const authPrefix = "Bearer "
if strings.HasPrefix(authorizationHeader, authPrefix) {
    reqToken = authorizationHeader[len(authPrefix):]
}
err := lib.VerifyIDToken(ma.fbapp, reqToken)
...

Assuming that "" will fail happily in a non-side-effecty way, you could do that without breaking your control flow and basically make a missing auth token the same as a bad auth token.

cbll:

a panic due to looking at a slice index that doesn't exist isn't pretty...

Indeed, hence why I am learning :)!

Alternatively, use empty values:

Thought of this, but seemed a bit javascripty to me. But yeah looks a bit better in the flow, I can see that.

Redundancy_:

I feel like the better answer is /u/titpetric's with a proper test and early return, I'm just giving you some options.

cbll:

Gotcha. Thanks for the help!


入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

691 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传