Browse Source

增加jwt主动失效功能(next:多点登录限制

pixel 5 years ago
parent
commit
4aa116cd7a

+ 28 - 0
QMPlusServer/controller/api/sys_jwt_blacklist.go

@@ -0,0 +1,28 @@
+package api
+
+import (
+	"fmt"
+	"gin-vue-admin/controller/servers"
+	"gin-vue-admin/model/sysModel"
+	"github.com/gin-gonic/gin"
+)
+
+// @Tags jwt
+// @Summary jwt加入黑名单
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
+// @Router /jwt/jsonInBlacklist [post]
+func JsonInBlacklist(c *gin.Context){
+	token := c.Request.Header.Get("x-token")
+	ModelJwt := sysModel.JwtBlacklist{
+		Jwt:token,
+	}
+	err := ModelJwt.JsonInBlacklist()
+	if err != nil {
+		servers.ReportFormat(c, false, fmt.Sprintf("jwt作废失败,%v", err), gin.H{})
+	} else {
+		servers.ReportFormat(c, true, "jwt作废成功", gin.H{})
+	}
+}

+ 2 - 1
QMPlusServer/init/initRouter/init_router.go

@@ -24,6 +24,7 @@ func InitRouter() *gin.Engine {
 	router.InitApiRouter(ApiGroup)                   // 注册功能api路由
 	router.InitFileUploadAndDownloadRouter(ApiGroup) // 文件上传下载功能路由
 	router.InitWorkflowRouter(ApiGroup)              // 工作流相关路由
-	router.InitCasbinRouter(ApiGroup)
+	router.InitCasbinRouter(ApiGroup)                // 权限相关路由
+	router.InitJwtRouter(ApiGroup)                   // jwt相关路由
 	return Router
 }

+ 1 - 0
QMPlusServer/init/registTable/regist_table.go

@@ -13,6 +13,7 @@ func RegistTable(db *gorm.DB) {
 		sysModel.SysMenu{},
 		sysModel.SysApi{},
 		sysModel.SysBaseMenu{},
+		sysModel.JwtBlacklist{},
 		dbModel.ExaFileUploadAndDownload{},
 		sysModel.SysWorkflow{},
 		sysModel.SysWorkflowStepInfo{},

+ 12 - 0
QMPlusServer/middleware/jwt.go

@@ -3,6 +3,7 @@ package middleware
 import (
 	"errors"
 	"gin-vue-admin/controller/servers"
+	"gin-vue-admin/model/sysModel"
 	"github.com/dgrijalva/jwt-go"
 	"github.com/gin-gonic/gin"
 	uuid "github.com/satori/go.uuid"
@@ -13,6 +14,9 @@ func JWTAuth() gin.HandlerFunc {
 	return func(c *gin.Context) {
 		// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localSstorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
 		token := c.Request.Header.Get("x-token")
+		ModelToken := sysModel.JwtBlacklist{
+			Jwt:token,
+		}
 		if token == "" {
 			servers.ReportFormat(c, false, "未登录或非法访问", gin.H{
 				"reload": true,
@@ -20,6 +24,13 @@ func JWTAuth() gin.HandlerFunc {
 			c.Abort()
 			return
 		}
+		if ModelToken.IsBlacklist(token){
+			servers.ReportFormat(c, false, "授权已失效", gin.H{
+				"reload": true,
+			})
+			c.Abort()
+			return
+		}
 		j := NewJWT()
 		// parseToken 解析token包含的信息
 		claims, err := j.ParseToken(token)
@@ -135,3 +146,4 @@ func (j *JWT) RefreshToken(tokenString string) (string, error) {
 	}
 	return "", TokenInvalid
 }
+

+ 23 - 0
QMPlusServer/model/sysModel/sys_jwt_blacklist.go

@@ -0,0 +1,23 @@
+package sysModel
+
+import (
+	"gin-vue-admin/init/qmsql"
+	"github.com/jinzhu/gorm"
+)
+
+type JwtBlacklist struct {
+	gorm.Model
+	Jwt string `gorm:"type:text"`
+}
+
+func(j *JwtBlacklist)JsonInBlacklist()(err error){
+	err = qmsql.DEFAULTDB.Create(j).Error
+	return
+}
+
+
+//判断JWT是否在黑名单内部
+func (j *JwtBlacklist)IsBlacklist(Jwt string)(bool){
+	isNotFound := qmsql.DEFAULTDB.Where("jwt = ?",Jwt).First(j).RecordNotFound()
+	return !isNotFound
+}

+ 3 - 3
QMPlusServer/model/sysModel/sys_user.go

@@ -29,9 +29,9 @@ type SysUser struct {
 func (u *SysUser) Regist() (err error, userInter *SysUser) {
 	var user SysUser
 	//判断用户名是否注册
-	findErr := qmsql.DEFAULTDB.Where("username = ?", u.Username).First(&user).Error
-	//err为nil表明读取到了 不能注册
-	if findErr == nil {
+	notResigt := qmsql.DEFAULTDB.Where("username = ?", u.Username).First(&user).RecordNotFound()
+	//notResigt为false表明读取到了 不能注册
+	if !notResigt {
 		return errors.New("用户名已注册"), nil
 	} else {
 		// 否则 附加uuid 密码md5简单加密 注册

+ 14 - 0
QMPlusServer/router/sys_jwt.go

@@ -0,0 +1,14 @@
+package router
+
+import (
+	"gin-vue-admin/controller/api"
+	"gin-vue-admin/middleware"
+	"github.com/gin-gonic/gin"
+)
+
+func InitJwtRouter(Router *gin.RouterGroup) {
+	ApiRouter := Router.Group("jwt").Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
+	{
+		ApiRouter.POST("jsonInBlacklist", api.JsonInBlacklist)   //jwt加入黑名单
+	}
+}

+ 16 - 0
QMPlusVuePage/src/api/jwt.js

@@ -0,0 +1,16 @@
+import service from '@/utils/request'
+
+// @Tags jwt
+// @Summary jwt加入黑名单
+// @Security ApiKeyAuth
+// @accept application/json
+// @Produce application/json
+// @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
+// @Router /jwt/jsonInBlacklist [post]
+
+export const jsonInBlacklist = () => {
+    return service({
+        url: "/jwt/jsonInBlacklist",
+        method: 'post',
+    })
+}

+ 7 - 0
QMPlusVuePage/src/store/module/user.js

@@ -1,4 +1,5 @@
 import { login } from '@/api/user'
+import { jsonInBlacklist } from '@/api/jwt'
 import router from '@/router/index'
 export const user = {
     namespaced: true,
@@ -52,6 +53,12 @@ export const user = {
                     router.push({ path: '/layout/dashbord' })
                 }
             }
+        },
+        async LoginOut({ commit }) {
+            const res = await jsonInBlacklist()
+            if (res.success) {
+                commit("LoginOut")
+            }
         }
     },
     getters: {

+ 6 - 4
QMPlusVuePage/src/utils/request.js

@@ -61,11 +61,13 @@ service.interceptors.response.use(
             Message({
                 showClose: true,
                 message: response.data.msg,
-                type: 'error'
+                type: 'error',
+                onClose: () => {
+                    if (response.data.data && response.data.data.reload) {
+                        store.commit('user/LoginOut')
+                    }
+                }
             })
-            if (response.data.data && response.data.data.reload) {
-                store.commit('user/LoginOut')
-            }
             return Promise.reject(response.data.msg)
         }
     },

+ 2 - 2
QMPlusVuePage/src/view/layout/index.vue

@@ -51,7 +51,7 @@
 
 <script>
 import Aside from '@/view/layout/aside'
-import { mapGetters, mapMutations } from 'vuex'
+import { mapGetters, mapActions } from 'vuex'
 export default {
   name: 'Layout',
   data() {
@@ -63,7 +63,7 @@ export default {
     Aside
   },
   methods: {
-    ...mapMutations('user', ['LoginOut']),
+    ...mapActions('user', ['LoginOut']),
     totalCollapse() {
       this.isCollapse = !this.isCollapse
       this.$bus.emit('totalCollapse')