基于Golang开发一个轻量级登录库/框架的完整攻略如下:
1. 确定需求
在开始开发之前,需要确定产品的需求。这个登录库需要实现的功能包括:
- 注册用户账号
- 用户登录验证
- 用户信息查询
- 用户权限控制
- 登出
2. 选择框架
选择适合自己的框架是开发的基础,对于Golang而言,一般会使用gin框架,因为gin拥有出色的性能和灵活的中间件机制。
3. 数据库设计
设计数据库,此处我们使用MySQL数据库,设计用户表(User)和用户角色表(Role)。
CREATE TABLE `User` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username_UNIQUE` (`username`)
) ENGINE=InnoDB;
CREATE TABLE `Role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB;
4. 开发登录模块
注册用户账号
在handlers目录下创建一个user.go文件,实现注册用户的逻辑:
type UserController struct {
UserService userService.UserService
}
func (controller *UserController) Register(c *gin.Context) {
var user models.User
c.BindJSON(&user)
// 调用UserService的Register方法
err := controller.UserService.Register(user)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "register successfully",
})
}
用户登录验证
继续在handlers目录下user.go文件中编写用户登录逻辑:
func (controller *UserController) Login(c *gin.Context) {
var user models.User
c.BindJSON(&user)
if controller.UserService.Login(user) {
//在登录验证成功后创建一个jwttoken,返回给客户端
tokenString, _ := middlewares.CreateToken(user.UserName)
c.JSON(http.StatusOK, gin.H{
"token": tokenString,
})
} else {
c.JSON(http.StatusUnauthorized, nil)
}
}
用户信息查询
实现用户信息查询:
func (controller *UserController) GetUser(c *gin.Context) {
//从jwt中获取用户名
userName := utils.GetUserNameFromToken(c.Request.Header["Authorization"][0])
user, err := controller.UserService.GetUser(userName)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, user)
}
用户权限控制
在实现权限控制前,需要在UserRole表中添加用户和角色的关联关系。
//获取指定用户的角色列表
func (controller *UserController) GetUserRoles(userId int) ([]string, error) {
roles, err := controller.UserService.GetUserRoles(userId)
if err != nil {
return nil, err
}
roleNames := make([]string, len(roles))
for i, role := range roles {
roleNames[i] = role.Name
}
return roleNames, nil
}
然后在最外层middlewares中实现基于Token的身份验证和权限控制:
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.Request.Header["Authorization"][0]
claims, err := utils.ParseToken(tokenString)
if err != nil {
c.JSON(http.StatusUnauthorized, nil)
c.Abort()
return
} else if time.Now().Unix() > claims.ExpiresAt {
c.JSON(http.StatusUnauthorized, gin.H{
"message": "token expired",
})
c.Abort()
return
}
c.Set("userName", claims.Username)
c.Next()
}
}
func PermissionMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
userName := c.GetString("userName")
if !userService.HasPermission(userName, c.FullPath()) {
c.JSON(http.StatusForbidden, gin.H{
"message": "Permission denied",
})
c.Abort()
return
}
c.Next()
}
}
登出
移除Token即可。
func (controller *UserController) Logout(c *gin.Context) {
//Todo: 移除Token即可
c.JSON(http.StatusOK, gin.H{
"message": "Logout successfully",
})
}
5. 示例说明
我们将实现一个简单的web应用来演示该登录框架,该应用中包含一个index页面和admin页面,index页面任何人都可以浏览,但是只有管理员才能够访问admin页面。
index页面
func IndexHTMLHandler(c *gin.Context) {
indexHTML := `
<html>
<head>
<meta charset="UTF-8">
<title>Index Page</title>
</head>
<body>
<h1>Welcome to Index Page, everybody!</h1>
</body>
</html>`
c.Data(http.StatusOK, "text/html; charset=utf8", []byte(indexHTML))
}
admin页面
func AdminHTMLHandler(c *gin.Context) {
adminHTML := `
<html>
<head>
<meta charset="UTF-8">
<title>Admin Page</title>
</head>
<body>
<h1>Welcome to Admin Page, administrator!</h1>
</body>
</html>`
c.Data(http.StatusOK, "text/html; charset=utf8", []byte(adminHTML))
}
登录页面
使用html页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login Page</title>
</head>
<body>
<form action="" id="login">
<div>
<label for="username">用户名:</label>
<input type="text" id="username" name="username" require>
</div>
<div>
<label for="password">密码:</label>
<input type="password" id="password" name="password" require>
</div>
<button type="submit">登录</button>
</form>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#login').submit(function(e) {
e.preventDefault();
$.ajax({
url: '/login',
type: 'POST',
data: JSON.stringify({
'username': $('#username').val(),
'password': $('#password').val()
}),
contentType: "application/json",
dataType: "json",
success: function(data) {
localStorage.setItem("token", data.token);
window.location.href = '/';
},
error: function(request, status, error) {
alert("登录失败,请检查用户名和密码!");
}
});
});
});
</script>
</body>
</html>
实现
func setupRouter() *gin.Engine {
router := gin.Default()
userController := &controllers.UserController{UserService: &userService.UserServiceImpl{}}
//注册路由
router.POST("/register", userController.Register)
//登录路由
router.POST("/login", userController.Login)
/*中间件*/
middleware := middlewares.AuthMiddleware()
router.Use(middleware)
router.Use(middlewares.PermissionMiddleware())
router.Static("/", "./web/static/")
router.GET("/index.html", handlers.IndexHTMLHandler)
router.GET("/admin.html", handlers.AdminHTMLHandler)
router.GET("/user", userController.GetUser)
return router
}
func main() {
db := database.InitDatabase()
defer db.Close()
utils.InitJwt()
server := &http.Server{
Addr: ":8080",
Handler: setupRouter(),
}
err := server.ListenAndServe()
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
接下来,你就可以访问'/index.html'了,任何人都可以访问。当你访问'/admin.html'时,若请求的Token不具有访问/admin.html的权限,服务器将会返回状态码403,否则,将会返回admin.html文件。
至此,我们已经通过Golang成功构建了一个轻量级的登录库/框架,该框架具有基本的用户注册、登录、权限控制和登出功能,可以很方便的集成到你自己的应用中。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于Golang开发一个轻量级登录库/框架 - Python技术站