dongpang4470 2015-06-06 18:53
浏览 58
已采纳

Web应用中的Go身份验证逻辑模式

I want to determine a simple and useful pattern for user authentication in a web app being written in golang.

I have come up with two patterns. First one is enabling the programmer to have his functions separate form the authentication logic, and has cleaner HandleFunc parts in main() that one can see only by loking main() to see what parts are under authentication control.

Second one is making programmer include a decision in every function deal with authentication required urls. An if statement checks by a authp() function defined else where.

Which one is better pattern for such necessity?

What are the better patterns for this job?

Is it even possible to pass a function to http.HandleFunc that has signature other than func urlFunc (ResponseWriter, *Request) bu like func urlFunc (successFunc, failFunc) or func urlFunc (ResponseWriter, *Request, successFunc, failFunc) as in authenticationGateKeeper function of First Way below, if not a suitable workaround for that?

//First Way
package main

func authGateKeeper(successFunc, failFunc) {
    if (authp()) {
        successFunc
    } else {
        failFunc
    }
}

func authp() boolean {
    //authentication logic, db query, or session check etc.
}

//usage in main
http.HandleFunc("/", authGateKeeper)



//Second Way; other alternative, in each function check pattern
func f(w, r) {
    if (authp()) {
    //function's processes
    } else {
    //the fail case function or processes
    }
}

func authp() boolean {
    //authentication logic, db query, or session check etc.
}

//usage in main
http.HandleFunc("/", f)
  • 写回答

1条回答 默认 最新

  • 普通网友 2015-06-07 00:36
    关注

    There are many ways to spin this, and it's arguable whether one is outright "better". I'd strongly suggest writing some middleware that wraps your routes and enforces the check, calling the wrapped handler only on success.

    Note that I'm going to make a few assumptions here as you haven't told us how you're managing sessions (cookies? server-side?) and/or what kind of authorization you might need on top of authentication.

    // Middleware - a function that sits in the 'middle' of your request processing.
    func RequireAuth(h http.Handler) http.Handler) {
        fn := func(w http.ResponseWriter, r *http.Request) {
            // Assuming gorilla/sessions
            session, err := store.Get("name", r)
            if err != nil {
                // Raise HTTP 500
                return
            }
    
            // We'll assume you're storing the userID in the cookie|server session
            // upon login elsewhere.
            id := session.Values["userID"]
            // Probably returns a *yourapp.User
            user, err := db.GetUser(id)
            if err != nil {
                // Raise HTTP 500
                return
            }
    
            if user == nil {
                http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
                // Don't forget these 'naked' returns - if you miss one, your 
                // handler will keep processing beyond the error and result in
                // unintended side effects
                return
            }
    
            // Further checks here - i.e. checking user.Active == true, etc.
    
            // The userID matches one in the DB, so let's proceed
            h.ServeHTTP(w, r)
        }
    
        return http.HandlerFunc(fn)
    }
    
    // And in your router - assuming just vanilla net/http
    http.Handle("/", RequireAuth(yourHandlerFunc))
    http.Handle("/", RequireAuth(someOtherHandler))
    // Note that using gorilla/mux or goji can help give you "subrouters" so you
    // don't have to wrap every single route with your middleware (messy, error prone)
    

    I'd also suggest some reading on Go middleware1 composition2 which will help you in the future.

    If you want to call a custom error page, just write a handler - e.g. UnauthorizedHandler that satisfies http.Handler and just call UnauthorizedHandler.ServeHTTP(w, r) instead of http.Error along the way.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥200 uniapp长期运行卡死问题解决
  • ¥15 latex怎么处理论文引理引用参考文献
  • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?