登出登入bug修复

This commit is contained in:
2025-06-26 20:33:42 +08:00
parent cd7f61d141
commit a10173d98a
8 changed files with 248 additions and 169 deletions
+4 -1
View File
@@ -86,11 +86,14 @@ func main() {
// 自定义 404 页面(需要提前加载模板) // 自定义 404 页面(需要提前加载模板)
r.NoRoute(func(ctx *gin.Context) { r.NoRoute(func(ctx *gin.Context) {
ctx.HTML(404, "error_404.html", gin.H{}) ctx.HTML(404, "error_404.html", gin.H{})
}) })
r.Use(func(ctx *gin.Context) {
routers.Fitst_use(ctx)
})
routers.Def_router(r.Group("/")) //分组路由传递到def_routers。go routers.Def_router(r.Group("/")) //分组路由传递到def_routers。go
routers.Api_router(r.Group("/api/")) //分组路由传递到api_routers。go
var http_port = models.Wed_configs.Host + ":" + models.Wed_configs.Port var http_port = models.Wed_configs.Host + ":" + models.Wed_configs.Port
var gin_port = "0.0.0.0" + ":" + models.Wed_configs.Port var gin_port = "0.0.0.0" + ":" + models.Wed_configs.Port
+8 -2
View File
@@ -77,6 +77,8 @@ func V1_user_api(r *gin.RouterGroup) {
user.Name = newUser.Name user.Name = newUser.Name
if models.DB.Where(&user).First(&user).Error == nil { if models.DB.Where(&user).First(&user).Error == nil {
// 有数据 // 有数据
fmt.Println(user)
fmt.Println(newUser)
if user.Pass == newUser.Pass { if user.Pass == newUser.Pass {
//成功登录 //成功登录
@@ -149,7 +151,9 @@ func V1_user_api(r *gin.RouterGroup) {
//先判断是否已经登录 //先判断是否已经登录
//获取中间件处理的结果 //获取中间件处理的结果
_, is_login := ctx.Get("user_info") user_info, is_login := ctx.Get("user_info")
fmt.Println(is_login)
fmt.Println(user_info)
if is_login == true { if is_login == true {
//fmt.Println("loged") //fmt.Println("loged")
cookie_any, _ := ctx.Get("cookie") //这个cookie在中间件已经判断为有效的,否则is_login不可能为true,所以直接在数据库删除应该是安全的 cookie_any, _ := ctx.Get("cookie") //这个cookie在中间件已经判断为有效的,否则is_login不可能为true,所以直接在数据库删除应该是安全的
@@ -163,11 +167,13 @@ func V1_user_api(r *gin.RouterGroup) {
Return_json(ctx, "api_ok", nil) Return_json(ctx, "api_ok", nil)
} else { } else {
Return_json(ctx, "json_error", nil) Return_json(ctx, "json_error", nil)
} }
} else { } else {
//ctx.SetCookie("user", "", -1, "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
Return_json(ctx, "user_no_sign", nil) Return_json(ctx, "user_no_sign", nil)
} }
-102
View File
@@ -5,113 +5,11 @@ import (
"net/http" "net/http"
"saas/models" "saas/models"
"strconv" "strconv"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/mitchellh/mapstructure"
) )
func Def_router(r *gin.RouterGroup) { func Def_router(r *gin.RouterGroup) {
r.Use(func(ctx *gin.Context) {
cookie_vel := ""
//读取用户cookie,判断用户是否已登录
cookie_s, _ := ctx.Cookie("user")
cookie_vel = cookie_s
//转换传进来的数据
var jsonData map[string]interface{}
if err := ctx.ShouldBindJSON(&jsonData); err == nil {
//分离数据
var cookie_t models.Cookie
if err = mapstructure.Decode(jsonData["cookie"], &cookie_t); err == nil {
cookie_vel = cookie_t.Value
}
var data_t map[string]interface{}
if err = mapstructure.Decode(jsonData["data"], &data_t); err == nil {
ctx.Set("data", &data_t)
}
}
//fmt.Println(cookie_vel)
if cookie_vel != "" {
var cookie models.Cookie
cookie.Value = cookie_vel
if models.DB.Where(&cookie).First(&cookie).Error == nil {
// 有数据
//有cookie,判断cookie有效性
if cookie.ExpiresAt.After(time.Now()) {
// ExpiresAt 在当前时间之后(未过期)
//fmt.Println("Cookie 未过期")
//每次调用都更新cookie的最新状态 ,用于计算在线
var cookie_up models.Cookie
cookie_up.UpdatedAt = time.Now()
cookie_up.ExpiresAt = time.Now().Add(time.Duration(models.User_configs["cookie_timeout"].(int)) * time.Second) //计算过期时间
models.DB.Model(&models.Cookie{}).Where(&cookie).Updates(&cookie_up)
//更新前端cookie
ctx.SetCookie("user", cookie.Value, models.User_configs["cookie_timeout"].(int), "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.UpdatedAt = cookie_up.UpdatedAt
cookie.ExpiresAt = cookie_up.ExpiresAt
ctx.Set("cookie", cookie)
//读取用户权限信息
var user models.User
user.ID = cookie.UserID
if models.DB.Where(&user).First(&user).Error == nil {
//找到登录权限
//清除一些重要数据,避免传递的时候泄露
user.Pass = ""
// 读取用户info
var user_info models.User_info
user_info.UserID = cookie.UserID
if models.DB.Where(&user_info).First(&user_info).Error == nil {
// 有数据
//fmt.Println(user_info)
} else {
// 无数据
//创建一个默认info
user_info.AvatarPath = models.User_configs["def_avatar_path"].(string)
user_info.UserID = cookie.UserID
models.DB.Create(&user_info) // 传入指针
}
//写入当前登录的用户信息 传递给下一个组件
ctx.Set("user_info", &user_info)
ctx.Set("user", &user)
} else {
//找不到登录权限?? 可能被封号?
//删除前端cookie
ctx.SetCookie("user", "", -1, "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.Value = ""
cookie.ExpiresAt = time.Now()
ctx.Set("cookie", cookie)
}
} else {
// ExpiresAt 在当前时间之前或等于(已过期)
//fmt.Println("Cookie 已过期")
//删除数据库的cookie
models.DB.Delete(&cookie)
//删除前端cookie
ctx.SetCookie("user", "", -1, "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.Value = ""
cookie.ExpiresAt = time.Now()
ctx.Set("cookie", cookie)
}
} else {
//找不到cookie,未登录
//删除前端cookie
ctx.SetCookie("user", "", -1, "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.Value = ""
cookie.ExpiresAt = time.Now()
ctx.Set("cookie", cookie)
}
}
})
Api_router(r.Group("/api/")) //分组路由传递到api_routers。go
//无需权限的页面 //无需权限的页面
r.GET("/", func(ctx *gin.Context) { r.GET("/", func(ctx *gin.Context) {
+118
View File
@@ -0,0 +1,118 @@
package routers
import (
"fmt"
"saas/models"
"time"
"github.com/gin-gonic/gin"
"github.com/mitchellh/mapstructure"
)
func Fitst_use(ctx *gin.Context) {
cookie_vel := ""
//读取用户cookie,判断用户是否已登录
cookie_s, is_have_cookie := ctx.Cookie("user")
if is_have_cookie == nil {
cookie_vel = cookie_s
}
//转换传进来的数据
var jsonData map[string]interface{}
if err := ctx.ShouldBindJSON(&jsonData); err == nil {
//分离数据
var cookie_t models.Cookie
if err = mapstructure.Decode(jsonData["cookie"], &cookie_t); err == nil {
if cookie_t.Value != "" {
cookie_vel = cookie_t.Value
}
}
var data_t map[string]interface{}
if err = mapstructure.Decode(jsonData["data"], &data_t); err == nil {
ctx.Set("data", &data_t)
}
}
//fmt.Println(cookie_vel)
if cookie_vel != "" {
var cookie models.Cookie
cookie.Value = cookie_vel
if models.DB.Where(&cookie).First(&cookie).Error == nil {
// 有数据
//有cookie,判断cookie有效性
if cookie.ExpiresAt.After(time.Now()) {
// ExpiresAt 在当前时间之后(未过期)
//fmt.Println("Cookie 未过期")
//每次调用都更新cookie的最新状态 ,用于计算在线
var cookie_up models.Cookie
cookie_up.UpdatedAt = time.Now()
cookie_up.ExpiresAt = time.Now().Add(time.Duration(models.User_configs["cookie_timeout"].(int)) * time.Second) //计算过期时间
models.DB.Model(&models.Cookie{}).Where(&cookie).Updates(&cookie_up)
//更新前端cookie
ctx.SetCookie("user", cookie.Value, models.User_configs["cookie_timeout"].(int), "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.UpdatedAt = cookie_up.UpdatedAt
cookie.ExpiresAt = cookie_up.ExpiresAt
ctx.Set("cookie", cookie)
//读取用户权限信息
var user models.User
user.ID = cookie.UserID
if models.DB.Where(&user).First(&user).Error == nil {
//找到登录权限
//清除一些重要数据,避免传递的时候泄露
user.Pass = ""
// 读取用户info
var user_info models.User_info
user_info.UserID = cookie.UserID
if models.DB.Where(&user_info).First(&user_info).Error == nil {
// 有数据
//fmt.Println(user_info)
} else {
// 无数据
//创建一个默认info
user_info.AvatarPath = models.User_configs["def_avatar_path"].(string)
user_info.UserID = cookie.UserID
models.DB.Create(&user_info) // 传入指针
}
//写入当前登录的用户信息 传递给下一个组件
fmt.Println(user_info)
ctx.Set("user_info", &user_info)
ctx.Set("user", &user)
} else {
//找不到登录权限?? 可能被封号?
//删除前端cookie
ctx.SetCookie("user", "", -1, "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.Value = ""
cookie.ExpiresAt = time.Now()
ctx.Set("cookie", cookie)
}
} else {
// ExpiresAt 在当前时间之前或等于(已过期)
//fmt.Println("Cookie 已过期")
//删除数据库的cookie
models.DB.Delete(&cookie)
//删除前端cookie
ctx.SetCookie("user", "", -1, "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.Value = ""
cookie.ExpiresAt = time.Now()
ctx.Set("cookie", cookie)
}
} else {
//找不到cookie,未登录
//删除前端cookie
ctx.SetCookie("user", "", -1, "/", models.Wed_configs.Host, models.Wed_configs.Tls, true)
cookie.Value = ""
cookie.ExpiresAt = time.Now()
ctx.Set("cookie", cookie)
}
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ function post_json(path, json, callback) {
}, },
}) })
.then((response) => { .then((response) => {
console.log(response) //console.log(response)
re_data["statusCode"] = response.status; re_data["statusCode"] = response.status;
//载入服务器返回的数据 //载入服务器返回的数据
if (response.data) { if (response.data) {
+90 -37
View File
@@ -1,13 +1,13 @@
<footer class="footer footer-transparent d-print-none "> <footer class="footer footer-transparent d-print-none ">
<div class="container-xl"> <div class="container-xl">
<div class="row text-center align-items-center flex-row-reverse"> <div class="row text-center align-items-center flex-row-reverse">
<div class="col-lg-auto ms-lg-auto"> <div class="col-lg-auto ms-lg-auto">
<ul class="list-inline list-inline-dots mb-0"> <ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas/-/blob/main/readme.md?ref_type=heads" target="_blank" <li class="list-inline-item"><a
href="https://git.lmve.net/kevin/gin_saas/-/blob/main/readme.md?ref_type=heads" target="_blank"
class="link-secondary" rel="noopener">文档</a></li> class="link-secondary" rel="noopener">文档</a></li>
<li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas/-/blob/main/LICENSE?ref_type=heads" target="_blank" class="link-secondary">开源协议</a> <li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas/-/blob/main/LICENSE?ref_type=heads"
target="_blank" class="link-secondary">开源协议</a>
</li> </li>
<li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas" target="_blank" <li class="list-inline-item"><a href="https://git.lmve.net/kevin/gin_saas" target="_blank"
class="link-secondary" rel="noopener"> class="link-secondary" rel="noopener">
@@ -40,7 +40,8 @@
All rights reserved. All rights reserved.
</li> </li>
<li class="list-inline-item"> <li class="list-inline-item">
<a href="https://git.lmve.net/kevin/gin_saas/-/commits/main" target="_blank" class="link-secondary" rel="noopener"> <a href="https://git.lmve.net/kevin/gin_saas/-/commits/main" target="_blank" class="link-secondary"
rel="noopener">
v0.0.1 v0.0.1
</a> </a>
</li> </li>
@@ -50,19 +51,18 @@
</div> </div>
</footer> </footer>
<div class="offcanvas my_offcanvas_top alert alert-important alert-dismissible" role="alert" tabindex="-1" id="offcanvas"> <div class="offcanvas my_offcanvas_top" tabindex="-1" id="banner_alf" aria-labelledby="offcanvasTopLabel">
<div class="alert alert-dismissible alert-success" id="banner_alf_type">
<div class="d-flex"> <div class="d-flex">
<div> <div>
<!-- Download SVG icon from http://tabler-icons.io/i/check --> <!-- Download SVG icon from http://tabler-icons.io/i/check -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" <svg id="banner_alf_icon_success" class="d-none" xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M5 12l5 5l10 -10"></path> <path d="M5 12l5 5l10 -10"></path>
</svg> </svg>
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" <svg id="banner_alf_icon_warning" class="d-none" xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path <path
d="M10.24 3.957l-8.422 14.06a1.989 1.989 0 0 0 1.7 2.983h16.845a1.989 1.989 0 0 0 1.7 -2.983l-8.423 -14.06a1.989 1.989 0 0 0 -3.4 0z"> d="M10.24 3.957l-8.422 14.06a1.989 1.989 0 0 0 1.7 2.983h16.845a1.989 1.989 0 0 0 1.7 -2.983l-8.423 -14.06a1.989 1.989 0 0 0 -3.4 0z">
@@ -70,34 +70,30 @@
<path d="M12 9v4"></path> <path d="M12 9v4"></path>
<path d="M12 17h.01"></path> <path d="M12 17h.01"></path>
</svg> </svg>
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" <svg id="banner_alf_icon_danger" class="d-none" xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24"
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path>
<path d="M12 8v4"></path> <path d="M12 8v4"></path>
<path d="M12 16h.01"></path> <path d="M12 16h.01"></path>
</svg> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" <svg id="banner_alf_icon_info" class="d-none" xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
class="icon icon-tabler icons-tabler-outline icon-tabler-brand-hipchat"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path>
<path <path d="M12 9h.01"></path>
d="M17.802 17.292s.077 -.055 .2 -.149c1.843 -1.425 3 -3.49 3 -5.789c0 -4.286 -4.03 -7.764 -9 -7.764c-4.97 0 -9 3.478 -9 7.764c0 4.288 4.03 7.646 9 7.646c.424 0 1.12 -.028 2.088 -.084c1.262 .82 3.104 1.493 4.716 1.493c.499 0 .734 -.41 .414 -.828c-.486 -.596 -1.156 -1.551 -1.416 -2.29z" /> <path d="M11 12h1v4h1"></path>
<path d="M7.5 13.5c2.5 2.5 6.5 2.5 9 0" />
</svg> </svg>
</div> </div>
<div id="alertText"> <div id="banner_alf_text">
123 text
</div> </div>
</div> </div>
<a class="btn-close" data-bs-dismiss="offcanvas" aria-label="close"></a> <a class="btn-close" data-bs-dismiss="offcanvas" aria-label="close"></a>
</div> </div>
</div>
<!-- CSS files --> <!-- CSS files -->
<link href="/dist/css/tabler.min.css?1692870487" rel="stylesheet" /> <link href="/dist/css/tabler.min.css?1692870487" rel="stylesheet" />
<link href="/dist/css/tabler-flags.min.css?1692870487" rel="stylesheet" /> <link href="/dist/css/tabler-flags.min.css?1692870487" rel="stylesheet" />
@@ -114,6 +110,27 @@
body { body {
font-feature-settings: "cv03", "cv04", "cv11"; font-feature-settings: "cv03", "cv04", "cv11";
} }
.my_offcanvas_top {
height: 45px;
border-radius: 5px;
/* 四个角均为圆角 */
top: 50px;
right: 120px;
left: 120px;
transform: scaleY(0);
transform-origin: top center;
transition: transform 0.4s;
}
.my_offcanvas_top.show {
transform: scaleY(1);
}
</style> </style>
<!-- Libs JS --> <!-- Libs JS -->
<!-- <script src="/dist/libs/apexcharts/dist/apexcharts.min.js?1692870487" defer></script> <!-- <script src="/dist/libs/apexcharts/dist/apexcharts.min.js?1692870487" defer></script>
@@ -128,15 +145,51 @@
<script src="/dist/js/axios.min.js"></script> <script src="/dist/js/axios.min.js"></script>
<script src="/dist/js/jquery-3.7.1.min.js"></script> <script src="/dist/js/jquery-3.7.1.min.js"></script>
<script src="/dist/libs/bootstrap/dist/js/bootstrap.min.js"></script>
<script> <script>
var banner_offcanvas = new bootstrap.Offcanvas($('#banner_alf'), {
backdrop: false // 关闭背景层
});
function banner_alert(type, text, close) {
var ban_type = $('#banner_alf_type')
var ban_text = $('#banner_alf_text')
ban_type.removeClass('alert-success');
ban_type.removeClass('alert-warning');
ban_type.removeClass('alert-danger');
ban_type.removeClass('alert-info');
ban_type.addClass('alert-' + type);
ban_text.html(text);
$('#banner_alf_icon_success').addClass('d-none')
$('#banner_alf_icon_warning').addClass('d-none')
$('#banner_alf_icon_danger').addClass('d-none')
$('#banner_alf_icon_info').addClass('d-none')
switch (type){
case 'success':
$('#banner_alf_icon_success').removeClass('d-none')
break;
case 'warning':
$('#banner_alf_icon_warning').removeClass('d-none')
break;
case 'danger':
$('#banner_alf_icon_danger').removeClass('d-none')
break;
case 'info':
$('#banner_alf_icon_info').removeClass('d-none')
break;
}
banner_offcanvas.show();
setTimeout(() => {
banner_offcanvas?.hide()
}, close ? close : 1000);
}
//banner_alert('success', '123', 5000)
</script> </script>
+1 -1
View File
@@ -389,7 +389,7 @@
<link href="/dist/libs/cropper/cropper.min.css" rel="stylesheet"> <link href="/dist/libs/cropper/cropper.min.css" rel="stylesheet">
<!-- libs --> <!-- libs -->
<script src="/dist/libs/bootstrap/dist/js/bootstrap.min.js"></script>
<script> <script>
+8 -7
View File
@@ -71,12 +71,12 @@
<div id="pass_err" class="invalid-feedback">不能为空</div> <div id="pass_err" class="invalid-feedback">不能为空</div>
</div> </div>
</div> </div>
<div class="mb-2"> <!-- <div class="mb-2">
<label class="form-check"> <label class="form-check">
<input id="keep_login" type="checkbox" class="form-check-input" /> <input id="keep_login" type="checkbox" class="form-check-input" />
<span class="form-check-label">保持登录</span> <span class="form-check-label">保持登录</span>
</label> </label>
</div> </div> -->
<div class="form-footer"> <div class="form-footer">
<button onclick="sign_in()" class="btn btn-primary w-100">登录</button> <button onclick="sign_in()" class="btn btn-primary w-100">登录</button>
</div> </div>
@@ -160,20 +160,21 @@
post_json("/user/login", { post_json("/user/login", {
username: username_dom.value, username: username_dom.value,
password: password_dom.value, password: password_dom.value,
is_keep_login: keep_login_dom.checked is_keep_login: true
}, (c) => { }, (c) => {
if (c.statusCode == 200) { if (c.statusCode == 200) {
if (c.data.err_code == 0) { if (c.data.err_code == 0) {
save_json("cookie", c.data.return.cookie) //save_json("cookie", c.data.return.cookie)
banner_alert('success', "登录成功",9500)
save_json("user_info", c.data.return.user_info) save_json("user_info", c.data.return.user_info)
setTimeout(() => { setTimeout(() => {
location.href = '/' location.href = '/'
}, 500); }, 1000);
} else { } else {
//this.$refs.footer.alert('warning', "账号或密码不正确") banner_alert('warning', "账号或密码不正确",3000)
} }
} else { } else {
//this.$refs.footer.alert('danger', "网络连接错误:" + c.statusCode) banner_alert('danger', "网络连接错误:" + c.statusCode,3000)
} }
}) })