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.

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

报告相同问题?

悬赏问题

  • ¥20 eclipse连接sap后代码跑出来空白
  • ¥20 谁能帮我挨个解读这个php语言编的代码什么意思?
  • ¥15 win10权限管理,限制普通用户使用删除功能
  • ¥15 minnio内存占用过大,内存没被回收(Windows环境)
  • ¥65 抖音咸鱼付款链接转码支付宝
  • ¥15 ubuntu22.04上安装ursim-3.15.8.106339遇到的问题
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥15 网络通信安全解决方案
  • ¥50 yalmip+Gurobi