Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用

目录

  • 引出
  • 使用token的权限验证方法
    • 流程
  • 用户、角色、权限表设计
    • 权限表
    • 角色表
    • 角色-权限关联表
    • 用户表
    • 查询用户的权限(四表联查)
    • 数据库的视图
  • 项目中的应用
    • 自定义注解
    • 拦截器
    • controller层
    • DTO返回给前端
      • 枚举类型的json化
      • 日期json问题
    • 实体类-DAO
  • 总结

引出


1.认证鉴权服务,注册中心,认证中心,鉴权中心;
2.用户,角色,权限表设计,数据库视图的使用;
3.项目中的应用,使用自定义注解+拦截器;
4.枚举类型的json化, @JsonFormat(shape = JsonFormat.Shape.OBJECT) @Getter

https://gitee.com/pet365/springboot-privs-token

在这里插入图片描述

使用token的权限验证方法

在这里插入图片描述

流程

在这里插入图片描述

用户、角色、权限表设计

用户和权限之间关系(多对多)

在这里插入图片描述

中间内容: 角色

在这里插入图片描述

(本系统中: user—》角色(one-to-Many)

在这里插入图片描述

权限表

在这里插入图片描述

在这里插入图片描述

角色表

在这里插入图片描述

在这里插入图片描述

角色-权限关联表

在这里插入图片描述

在这里插入图片描述

用户表

在这里插入图片描述

在这里插入图片描述

查询用户的权限(四表联查)

-- 用户角色-权限模型SELECT 
user_owner.username,privs_role_tab.role_name,privs_tab.privs_name
FROM user_owner
LEFT JOIN privs_role_tab ON user_owner.user_role = privs_role_tab.role_id
LEFT JOIN privs_relationship_tab ON privs_relationship_tab.rp_role = privs_role_tab.role_id
LEFT JOIN privs_tab ON privs_tab.privs_id=privs_relationship_tab.rp_privs

数据库的视图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

项目中的应用

https://gitee.com/pet365/springboot-privs-token

在这里插入图片描述

自定义注解

PrivsCheck.java文件

package com.tianju.auth.util;import java.lang.annotation.*;/*** 定义注解*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PrivsCheck {String value() default "";
}

拦截器

在这里插入图片描述

在这里插入图片描述

AuthInterceptor.java文件

package com.tianju.auth.interceptor;import cn.hutool.json.JSONUtil;
import com.tianju.auth.dto.HttpResp;
import com.tianju.auth.dto.ResultCode;
import com.tianju.auth.util.JwtUtil;
import com.tianju.auth.util.PrivsCheck;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {/**** @param request 请求* @param response 响应* @param handler =====>handler====>:class org.springframework.web.method.HandlerMethod*                com.tianju.auth.controller.UserController#findAllUsernames()*                类 的 findAllUsernames() 方法*                Method method = handlerMethod.getMethod();// controller里面的方法findAllUsernames 对象*                Annotation[] annotations = method.getDeclaredAnnotations();// 可以获得该方法上的所有注解* @return 是否拦截* @throws Exception token过期异常*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");response.setContentType("text/html;charset=utf-8");if (token==null){ // 如果没有token,返回falseresponse.getWriter().write(JSONUtil.toJsonStr(HttpResp.results(ResultCode.USER_NOT_LOGIN_ERROR, new Date(),"用户没有登陆异常")));return false;}// 存在的用户,检验token是否过期try {// 正常情况String username = JwtUtil.getClaim(token, "username");String privs = JwtUtil.getClaim(token, "privs");// 判断是否能够访问当前的方法log.info("用户权限{}",privs);// handler:com.tianju.auth.controller.UserController#findAllUsernames()log.debug("handler:{}",handler);HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();// controller里面的方法findAllUsernames 对象Annotation[] annotations = method.getDeclaredAnnotations();// 可以获得该方法上的所有注解/*** @org.springframework.web.bind.annotation.GetMapping(path=[], headers=[], name=, produces=[], params=[], value=[/findAllUsernames], consumes=[])* @io.swagger.annotations.ApiOperation(code=200, notes=, hidden=false, authorizations=[@io.swagger.annotations.Authorization(scopes=[@io.swagger.annotations.AuthorizationScope(scope=, description=)], value=)], httpMethod=, tags=[查询所有用户名], extensions=[@io.swagger.annotations.Extension(name=, properties=[@io.swagger.annotations.ExtensionProperty(parseValue=false, name=, value=)])], responseHeaders=[@io.swagger.annotations.ResponseHeader(name=, responseContainer=, description=, response=class java.lang.Void)], response=class java.lang.Void, responseReference=, responseContainer=, produces=, nickname=, ignoreJsonView=false, position=0, protocols=, consumes=, value=findAllUsernames)* @com.tianju.auth.util.PrivsCheck(value=findAllUsernames)*/
//            for (Annotation annotation: annotations) {
//                /**
//                 * @org.springframework.web.bind.annotation.GetMapping(path=[], headers=[], name=, produces=[], params=[], value=[/findAllUsernames], consumes=[])
//                 * @io.swagger.annotations.ApiOperation(code=200, notes=, hidden=false, authorizations=[@io.swagger.annotations.Authorization(scopes=[@io.swagger.annotations.AuthorizationScope(scope=, description=)], value=)], httpMethod=, tags=[查询所有用户名], extensions=[@io.swagger.annotations.Extension(name=, properties=[@io.swagger.annotations.ExtensionProperty(parseValue=false, name=, value=)])], responseHeaders=[@io.swagger.annotations.ResponseHeader(name=, responseContainer=, description=, response=class java.lang.Void)], response=class java.lang.Void, responseReference=, responseContainer=, produces=, nickname=, ignoreJsonView=false, position=0, protocols=, consumes=, value=findAllUsernames)
//                 * @com.tianju.auth.util.PrivsCheck(value=findAllUsernames)
//                 */
//            }PrivsCheck annotation = method.getDeclaredAnnotation(PrivsCheck.class);System.out.println(annotation.value());if (privs.contains(annotation.value())){ // 有此权限return true;}else {response.getWriter().write(JSONUtil.toJsonStr(HttpResp.results(ResultCode.USER_ACCESS_ERROR, new Date(),"对不起权限不足")));return false;}}catch (ExpiredJwtException e){// token过期response.getWriter().write(JSONUtil.toJsonStr(HttpResp.results(ResultCode.USER_LOGIN_TOKEN_EXPIRED_ERROR, new Date(),"token过期")));return false;}}
}

拦截器的配置AuthConfig.java文件

package com.tianju.auth.config;import com.tianju.auth.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AuthConfig implements WebMvcConfigurer {@Autowiredprivate AuthInterceptor authInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(authInterceptor).addPathPatterns("/api/**").excludePathPatterns("/api/user/login");}
}

controller层

package com.tianju.auth.controller;import com.tianju.auth.dto.HttpResp;
import com.tianju.auth.dto.ResultCode;
import com.tianju.auth.entity.UserPrivs;
import com.tianju.auth.service.IUserService;
import com.tianju.auth.util.JwtUtil;
import com.tianju.auth.util.PrivsCheck;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;@RestController
@RequestMapping("/api/user")
@Api(tags = "用户api接口")
public class UserController {@Autowiredprivate IUserService userService;@ApiOperation(value = "login",tags = "用户登录接口")@ApiImplicitParams({@ApiImplicitParam(name = "username",value = "用户名",required = true),@ApiImplicitParam(name = "password",value = "密码",required = true)})@GetMapping("/login")public HttpResp login(String username, String password, HttpServletResponse response){List<UserPrivs> users = userService.login(username, password);StringBuilder privs = new StringBuilder();users.forEach(userPrivs -> privs.append(userPrivs.getPrivsName()+","));System.out.println("用户权限:"+privs);privs.deleteCharAt(privs.length()-1);String token = JwtUtil.createToken(username, privs.toString(), 1000 * 60);response.addHeader("token", token);return HttpResp.results(ResultCode.USER_LOGIN_SUCCESS,new Date(),username);}@GetMapping("/findAllUsernames")@ApiOperation(value = "findAllUsernames",tags = "查询所有用户名")
//    @PrivsCheck("findAllUsernames")@PrivsCheck("findX") // 设置一个没有的权限public HttpResp findAllUsernames(){List<String> allUsernames = userService.findAllUsernames();return HttpResp.results(ResultCode.USER_QUERY_SUCCESS,new Date(),allUsernames);}
}

DTO返回给前端

枚举类型的json化

在这里插入图片描述

@JsonFormat(shape = JsonFormat.Shape.OBJECT)

package com.tianju.auth.dto;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;/*** 枚举类型,http请求的返回值*/
// 枚举类型的json化,需要有get方法
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
@Getter
public enum ResultCode {BOOK_RUSH_SUCCESS(20010,"图书抢购成功"),BOOK_RUSH_ERROR(3001,"图书抢购失败"),LUA_SCRIPT_ERROR(3002,"Lua脚本操作失败"),USER_FIND_ERROR(40010,"非法请求,布隆过滤器不通过"),USER_FIND_SUCCESS(20010,"查询用户名成功"),USER_QUERY_SUCCESS(25010,"查询所有用户名成功"),USER_LOGIN_ERROR(40030,"用户登陆失败"),USER_NOT_LOGIN_ERROR(40040,"用户没有登陆异常"),USER_LOGIN_TOKEN_EXPIRED_ERROR(42040,"token已过期异常"),USER_ACCESS_ERROR(45040,"用户权限异常"),USER_LOGIN_SUCCESS(20020,"用户登陆成功"),;@ApiModelProperty("状态码")private Integer code;@ApiModelProperty("提示信息")private String msg;private ResultCode(Integer code,String msg){this.code =code;this.msg = msg;}
}

日期json问题

@JsonFormat(timezone = “GMT+8”)

package com.tianju.auth.dto;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.Date;/*** 返回给前端的响应* @param <T>*/
@ApiModel("DTO返回数据")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HttpResp<T> implements Serializable {private ResultCode resultCode;@ApiModelProperty("time")@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",timezone = "GMT+8")private Date time;@ApiModelProperty("results")private T result;public static <T> HttpResp <T> results(ResultCode resultCode,Date time,T results){HttpResp httpResp = new HttpResp();httpResp.setResultCode(resultCode);httpResp.setTime(time);httpResp.setResult(results);return httpResp;}
}

实体类-DAO

package com.tianju.auth.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("user_privs_view")
public class UserPrivs {@TableField("username")private String username;@TableField("password")private String password;@TableField("role_name")private String roleName;@TableField("privs_name")private String privsName;
}

dao

package com.tianju.auth.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tianju.auth.entity.UserPrivs;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper extends BaseMapper<UserPrivs> {
}

总结

1.认证鉴权服务,注册中心,认证中心,鉴权中心;
2.用户,角色,权限表设计,数据库视图的使用;
3.项目中的应用,使用自定义注解+拦截器;
4.枚举类型的json化, @JsonFormat(shape = JsonFormat.Shape.OBJECT) @Getter

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/81696.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux usb设备固定端口号

Linux usb设备固定端口号 一:/sys/bus/usb/devices/二:设备信息三:固定usb设备名方法 一:/sys/bus/usb/devices/ 信息显示如下 1-0:1.0 1&#xff1a;表示 1 号总线&#xff0c;或者说 1 号 Root Hub0&#xff1a;表示端口号1&#xff1a;表示配置号0&#xff1a;表示接口号命…

flink+kafka+doris+springboot集成例子

目录 一、例子说明 1.1、概述 1.1、所需环境 1.2、执行流程 二、部署环境 2.1、中间件部署 2.1.1部署kakfa 2.1.1.1 上传解压kafka安装包 2.1.1.2 修改zookeeper.properties 2.1.1.3 修改server.properties 2.1.1.3 启动kafka 2.1.2、部署flink 2.1.2.1 上传解压f…

SpringBoot项目-个人博客系统的实现【下】

10.实现强制要求登陆 当用户访问 博客列表页和 博客详情页时, 如果用户当前尚未登陆, 就自动跳转到登陆页面 1.添加拦截器 public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletRespon…

根文件系统制作

1.官网下载工具 制作工具&#xff1a;busybox https://busybox.net/downloads/ 2.制作根文件系统 2.1准备工作 a.把压缩包放在FSP1M目录下&#xff0c;并解压 2.2正式开始 2.2.1配置交叉编译工具链 1. 打开Makefile文件 2. 修改ARCH &#xff1f;$(SUBARCH) &#xf…

Yolov5缺陷检测/目标检测 Jetson nx部署Triton server

使用AI目标检测进行缺陷检测时&#xff0c;部署到Jetson上即小巧算力还高&#xff0c;将训练好的模型转为tensorRT再部署到Jetson 上供http或GRPC调用。1 Jetson nx 刷机 找个ubuntu 系统NVIDIA官网下载安装Jetson 的sdkmanager一步步刷机即可。 本文刷的是JetPack 5.1, 其中包…

day03

#ifndef __SEQLIST_H__ #define __SEQLIST_H__#include <stdio.h> #include <string.h> #include <stdlib.h>#define MAX 40 typedef int datatype; typedef struct {datatype data[MAX];int len; }seqlist, *seqlistPtr;//创建顺序表 seqlistPtr list_creat…

vscode连接远程Linux服务器

文章目录 一、环境安装1.1 下载vscode1.2 下载vscode-sever 二、ssh链接2.1 安装Remote-SSH2.2 设置vscode ssh2.3 设置免密登录2.3.1 本地生成公私钥2.3.2 服务器端添加公钥 三、安装插件3.1 vscode安装插件3.1.1 在线安装插件3.1.2.1 下载插件3.1.2.2 安装插件 3.2 vscode-se…

Openlayers实战:判断共享单车是否在电子围栏内

共享单车方便了我们的日常生活,解决了后一公里的行程问题。为了解决共享单车乱放的问题,运营部门规划出一些围栏,配合到电子地图上即为电子围栏,只有放在围栏内才能停车结算,在我们的Openlayers实战示例中,即模拟这一场景。 效果图 源代码 /* * @Author: 大剑师兰特(x…

【Git】Git切换地址

如何切换git代码地址&#xff1f; 1、查看当前远程 url git remote -v执行命令后&#xff0c;可以看见当前有2个URL。 远程 URL 在一般情况下有两个&#xff0c;分别是 fetch 和 push。 fetch URL 是用于从远程仓库获取最新版本的数据。当您运行 git fetch 命令时&#xf…

ThreadPoolExecutor线程池详解

ThreadPoolExecutor线程池详解 1. 背景 项目最近的迭代中使用到了ThreadPoolExecutor线程池&#xff0c;之前都只是知道怎么用&#xff0c;没有了解过线程池的底层原理&#xff0c;项目刚上线&#xff0c;有时间整理一下线程池的用法&#xff0c;学习一下线程池的底层实现与工…

运行 Jmeter 文件生成 HTML 测试报告,我选择 ANT 工具

概述 ant 是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具&#xff0c;大多用于 Java 环境中的软件开发。 在与 Jmeter 生成的 jmx 文件配合使用中&#xff0c;ant 会完成jmx计划的执行和生成jtl文件&#xff0c;并将jtl文件转化为html页面进行查看。 还可…

Node.js |(三)Node.js API:path模块及Node.js 模块化 | 尚硅谷2023版Node.js零基础视频教程

学习视频&#xff1a;尚硅谷2023版Node.js零基础视频教程&#xff0c;nodejs新手到高手 文章目录 &#x1f4da;path模块&#x1f4da;Node.js模块化&#x1f407;介绍&#x1f407;模块暴露数据⭐️模块初体验⭐️暴露数据 &#x1f407;导入文件模块&#x1f407;导入文件夹的…

CAPL - XML和TestModule结合实现测试项可选

目录 目的:是否想实现如下面的功能呢? 一、.can和.cin文件中函数开发

C/C++面试总结

一、关键字static、const、extern、volatile作用 1、const 1.修饰常量 用const修饰的变量是不可变的&#xff0c;修饰后的变量只能使用&#xff0c;不能修改。 2.修饰指针 如果const位于*的左侧&#xff0c;eg&#xff1a;const int* a&#xff0c;则const就是用来修饰指针…

研发工程师玩转Kubernetes——hostPath

有别于《研发工程师玩转Kubernetes——emptyDir》一文中介绍的emptyDir&#xff0c;hostPath可以在同一个Node的不同Pod间共享卷。 下面的清单文件利用了Pod亲和性&#xff0c;让Pod集中到一个Node上。 apiVersion: apps/v1 kind: Deployment metadata:name: hostpath-deploy…

Adobe ColdFusion 反序列化漏洞复现(CVE-2023-29300)

0x01 产品简介 Adobe ColdFusion是美国奥多比&#xff08;Adobe&#xff09;公司的一套快速应用程序开发平台。该平台包括集成开发环境和脚本语言。 0x02 漏洞概述 Adobe ColdFusion存在代码问题漏洞&#xff0c;该漏洞源于受到不受信任数据反序列化漏洞的影响&#xff0c;攻击…

FinClip 支持小程序维度域名配置;桌面端体验活动进行中

FinClip 的使命是使您&#xff08;业务专家和开发人员&#xff09;能够通过小程序解决关键业务流程挑战&#xff0c;并完成数字化转型的相关操作。不妨让我们看看在本月的产品与市场发布亮点&#xff0c;看看是否有助于您实现目标。 产品方面的相关动向&#x1f447;&#x1f…

Kafka概论

前言 任何消息中间件&#xff0c;除了基础组件架构外&#xff0c;核心特性无非三个&#xff0c;消息可靠性、消息模型、吞吐量&#xff0c;本文要聊的正是这些东西&#xff0c;其余诸如API、下载安装、集群搭建等都是死的&#xff0c;而且会随着版本的变动而改变&#xff0c;这…

uni-app 封装api请求

前端封装api请求 前端封装 API 请求可以提高代码的可维护性和重用性&#xff0c;同时使得 API 调用更加简洁和易用。 下面是一种常见的前端封装 API 请求的方式&#xff1a; 创建一个 API 封装模块或类&#xff1a;可以使用 JavaScript 或 TypeScript 创建一个独立的模块或类来…

VoxWeekly|The Sandbox 生态周报|20230731

欢迎来到由 The Sandbox 发布的《VoxWeekly》。我们会在每周发布&#xff0c;对上一周 The Sandbox 生态系统所发生的事情进行总结。 如果你喜欢我们内容&#xff0c;欢迎与朋友和家人分享。请订阅我们的 Medium 、关注我们的 Twitter&#xff0c;并加入 Discord 社区&#xf…