Golang仿云盘项目-4账号系统与鉴权(1)-解决:登录404notfound

4.1 账号系统功能

解决:登录 404 not found
本文来自博客园,作者:Arway,转载请注明原文链接:https://www.cnblogs.com/cenjw/p/16490891.html

Golang仿云盘项目-4账号系统与鉴权(1)-解决:登录404notfound
  • 支持用户注册、登录
  • 支持用户Session鉴权
  • 用户数据资源隔离

用户表设计

CREATE TABLE tbl_user (
  id int(11) NOT NULL AUTO_INCREMENT,
  user_name varchar(64) NOT NULL DEFAULT '' COMMENT '用户名',
  user_pwd varchar(256) NOT NULL DEFAULT '' COMMENT '用户encoded密码',
  email varchar(64) DEFAULT '' COMMENT '邮箱',
  phone varchar(128) DEFAULT '' COMMENT '手机号',
  email_validated tinyint(1) DEFAULT 0 COMMENT '邮箱是否已验证',
  phone_validated tinyint(1) DEFAULT 0 COMMENT '手机号是否已验证',
  signup_at datetime DEFAULT CURRENT_TIMESTAMP COMMENT '注册日期',
  last_active datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后活跃时间戳',
  profile text COMMENT '用户属性',
  status int(11) NOT NULL DEFAULT '0' COMMENT '账户状态(启用/禁用/锁定/标记删除等)',
  PRIMARY KEY (id),
  UNIQUE KEY idx_username (user_name),
  KEY idx_status (status)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

4.2 用户注册/登录接口

注册接口

db/user.go

点击查看代码

// UserSignup: 通过用户名和密码完成user表的注册
func UserSignup(username, password string) bool {
    // 插入一条用户数据
    stmt, err := mydb.DBConn().Prepare("INSERT ignore INTO tbl_user(user_name, user_pwd)" +
                          "VALUES(?,?)")
    if err != nil {
        fmt.Println("Failed to insert, err: " + err.Error())
        return false
    }
    defer stmt.Close()

    ret, err := stmt.Exec(username, password)
    if err != nil {
        fmt.Println("Failed to insert, err: " + err.Error())
        return false
    }

    // 校验是否注册成功(重复注册也当做注册失败)
    if rows, err := ret.RowsAffected(); nil == err && rows > 0 {
        return true
    }
    return false
}

// 用于处理用户请求的一些handler
handler/user.go

点击查看代码

// SignupHandler : 处理用户注册请求
func SignupHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
        data, err := ioutil.ReadFile("./static/view/signup.html")
        if err != nil {
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        w.Write(data)
        return
    }

    r.ParseForm()

    username := r.Form.Get("username")
    passwd := r.Form.Get("password")

    if len(username) < 3 || len(passwd) < 5 {
        w.Write([]byte("Invalid parameter"))
        return
    }

    // 对密码进行加盐及取Sha1值加密
    encPasswd := util.Sha1([]byte(passwd + pwdSalt))
    // 将用户信息注册到用户表中
    suc := dblayer.UserSignup(username, encPasswd)
    if suc {
        w.Write([]byte("SUCCESS"))
    } else {
        w.Write([]byte("FAILED"))
    }
}

登录接口

  1. 校验用户名和密码
    比较请求上传参数中的数据和从数据库查出来的数据
  2. 生成访问凭证(token)
-- 创建用户token表
CREATE TABLE tbl_user_token (
    id int(11) NOT NULL AUTO_INCREMENT,
  user_name varchar(64) NOT NULL DEFAULT '' COMMENT '用户名',
  user_token char(40) NOT NULL DEFAULT '' COMMENT '用户登录token',
    PRIMARY KEY (id),
  UNIQUE KEY idx_username (user_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

replace: token 可重复生成且插入
3. 登录后重定向回首页
handler/user.go
处理登录请求点击查看代码

// SignInHandler : 登录接口
func SignInHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
        http.Redirect(w, r, "/static/view/signin.html", http.StatusFound)
        return
    }

    r.ParseForm()
    username := r.Form.Get("username")
    password := r.Form.Get("password")

    encPasswd := util.Sha1([]byte(password + pwdSalt))

    // 1. 校验用户名及密码
    pwdChecked := dblayer.UserSignin(username, encPasswd)
    if !pwdChecked {
        w.Write([]byte("FAILED"))
        return
    }

    // 2. 生成访问凭证(token)
    token := GenToken(username)
    upRes := dblayer.UpdateToken(username, token)
    if !upRes {
        w.Write([]byte("FAILED"))
        return
    }

    // 3. 登录成功后重定向到首页
    // w.Write([]byte("http://" + r.Host + "/static/view/home.html"))
    resp := util.RespMsg{
        Code: 0,
        Msg: "OK",
        Data: struct{
            Location string
            Username string
            Token string
        }{
            Location: "http://" + r.Host + "/static/view/home.html",
            Username: username,
            Token: token,
        },
    }
    w.Write(resp.JSONBytes())
}

用户信息查询接口

handler/user.go

点击查看代码

func UserInfoHandler(w http.ResponseWriter, r *http.Request) {
    // 1. 解析参数
    r.ParseForm()
    username := r.Form.Get("username")
    token := r.Form.Get("token")

    fmt.Printf("username: %v\n", username)

    // 2.验证token是否有效
    if !isTokenValid(token) {
        w.WriteHeader(http.StatusForbidden)
        return
    }

    // 3. 查询用户信息
    user, err := dblayer.GetUserInfo(username)
    fmt.Printf("user: %v", user)
    if err != nil {
        w.WriteHeader(http.StatusForbidden)
        return
    }

    // 4. 组装并且响应用户数据
    resp := util.RespMsg{
        Code: 0,
        Msg: "OK",
        Data: user,
    }
    w.Write(resp.JSONBytes())
}

本文来自博客园,作者:Arway,转载请注明原文链接:https://www.cnblogs.com/cenjw/p/16490891.html

解决:登录 404 not found

问题1:视频缺少了加载静态文件的部分内容,搜索了一波,go的http库有这么几个方法:

http.StripPrefix() 方法配合 http.Handle()http.HandleFunc() 可以实现 带路由前缀的文件服务
参考 https://cloud.tencent.com/developer/article/1351492

解决方法
在main.go文件的main方法中加上下面的代码

func main() {
    // static configure
    http.Handle("/static/",
            http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
    ...

问题2: 跳转home.html, 前端没有加载数据

Golang仿云盘项目-4账号系统与鉴权(1)-解决:登录404notfound

解决
查看了home.html文件发现没有传数据。。。
home.html

...

  window.onload = function () {
    var username = document.getElementById('username');
    $.ajax({
      // url: "/user/info?" + queryParams(),  注释掉这句
      url: "/user/info",
      type: "POST",
      // 加上data
      data: {username: localStorage.getItem("username"),
             token: localStorage.getItem("token")},
      error: function (jqXHR, textStatus, errorThrown) {
      ...

</code></pre><p>如果都不行,那就是这个js链接的问题。。。<br><img src="https://img2022.cnblogs.com/blog/2357964/202207/2357964-20220719211805806-1683536289.png"><br>兄弟们可以从<a href="http://www.htmleaf.com/js/jquery/jquery-2.0.0.html" rel="noopener">这里</a>找个能用的替换掉</p><h2 id="验证token的拦截器">验证token的拦截器</h2><p><code>handler/auth.go</code></p><pre><code class="language-go">// HTTPInterceptor: HTTP请求拦截器(函数类似Python的装饰器)
func HTTPInterceptor(h http.HandlerFunc) http.HandlerFunc {
    return http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            r.ParseForm()
            username := r.Form.Get("username")
            token := r.Form.Get("token")

            if len(username) < 3 || !isTokenValid(token) {
                w.WriteHeader(http.StatusForbidden)
                return
            }
            h(w, r)
        })
}
</code></pre><ol><li>是针对HTTP请求的</li><li>好处:以后所有要进行安全验证的接口都可以通过浏览器来实现,这样就可以实现统一认证,避免每个接口都要实现验证方法,节省时间和资源。</li></ol>

Original: https://www.cnblogs.com/cenjw/p/16490891.html
Author: micromatrix
Title: Golang仿云盘项目-4账号系统与鉴权(1)-解决:登录404notfound

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/712526/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球