自定义 Spring Cloud 0auth2.0

- 日理万妓 2024-04-17 19:14 21阅读 0赞

为什么自己实现oauth2.0?

因为spring cloud oauth2.0本身的缺点:

①如果想要控制到访问的每个URl,要进行大量的改造

②特别复杂,本省spring mvc拦截器,加上 网关拦截器,已经有很多拦截器了,但是它本身还有自己拦截器,要分析源码才能了解清楚

③抛错格式和本身自己系统不一致,经常遇到抛错格式不一致,然后又自己去寻找源码里面哪里抛错,并不能统一拦截抛错

④改造成本太大,本身理解oauth2.0的思想并不复杂,所以参考他的源码,自己改造了一套适合自己系统的oauth2.0

1. 首先就是数据库几张表的设计

  1. 整个鉴权中心一共五张表:
  2. ①权限表:
  3. CREATE TABLE \`oauth\_access\_info\` (
  4. \`access\_id\` bigint(20) NOT NULL AUTO\_INCREMENT COMMENT '权限id',
  5. \`client\_id\` varchar(100) DEFAULT NULL COMMENT '客户端id',
  6. \`user\_id\` varchar(100) DEFAULT NULL COMMENT '用户id',
  7. \`grant\_type\` varchar(100) NOT NULL COMMENT '支持多种类型用逗号隔开: authorization\_code(鉴权码模式),password(用户 名密码),client\_credentials(客户凭证),refresh\_token(刷新token模式)',

`scope` int(5) DEFAULT ‘1’ COMMENT ‘资源拥有范围: 1.全部信任 2.部分角色信任’,
`web_redirect_uri` varchar(255) DEFAULT NULL COMMENT ‘客户端的重定向URI,可为空’,
`token_validity` bigint(50) DEFAULT NULL COMMENT ‘token失效时间’,
`refresh_token_validity` bigint(50) DEFAULT NULL COMMENT ‘刷新token过期时间’,
`code_validity` bigint(50) DEFAULT NULL COMMENT ‘code失效时间’,
`create_time` datetime DEFAULT NULL COMMENT ‘数据创建时间’,
`update_time` datetime DEFAULT NULL COMMENT ‘数据修改时间’,
PRIMARY KEY (`access_id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COMMENT=’权限token详情表’;

权限表是和用户直接相关联的,所以他有用的id,其次就是权限表支持多种鉴权模式

用户名密码模式,就是拿用户名密码获取token, 客户凭证模式,其实也是校验用户的clientKey,clientSecret

鉴权码模式: 其实是第三方登录场景, 比如: 一个APP支持微信登录,首先用户在APP中申请微信登录,然后跳转到微信登录页面

  1. 用户输入完微信用户名和密码并且携带者APP跳转网页,请求微信服务器,微信服务器分配一个code,
  2. 然后重定向到那个APP页面,APP页面拿到code,去请求APP后台服务,后台服务拿着code,去请求微信获取token,
  3. 然后就可以拿着这个token,获取用户微信数据了

刷新token模式: 为什么刷新token还要归为一种模式,其实他是属于客户端拿着有效期内的token,来刷新拿到时长更久一些token

其实本身他分为两类: oauth模式鉴权和oauth2模式鉴权

资源拥有范围: 完全信任是可以请求资源服务的所有资源,简单来说就是可以请求所有接口, 部分角色信任,就是代表鉴权的时候

  1. 他只是可以访问部分资源数据

token,code,refresh_token,各自的时间不一样

②token,code表

CREATE TABLE `oauth_token_code` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`access_id` bigint(20) DEFAULT NULL COMMENT ‘权限id’,
`create_type` int(5) NOT NULL DEFAULT ‘2’ COMMENT ‘1 oauth2.0模式 2 oauth模式’,
`token` text COMMENT ‘token值’,
`code` text COMMENT ‘code值’,
`refresh_token` text COMMENT ‘刷新token’,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8mb4;

这里重点解释一下为什么要设置 create_type : 因为有可能一个客户端,可同时进行两种鉴权的,

  1. 所以要根据这种来区分他进行的是哪种鉴权

这个表因为经常访问,我现在是把他放在了redis里面

数据结构为 key ,value的形式

首先讲一下怎么确认是唯一token, 因为token生成有两种模式,所以 tokenId = 权限表id+create_type

这里为什么需要权限表id,因为后面进行拿到token获取权限表信息的时候,需要得到这个token对应的权限表id

key的组成为: tokenId_token value就是: 当前生成时间 从权限表得到失效时间进行设置key失效时间

③ 资源表:

CREATE TABLE `oauth_resource_info` (
`resource_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘资源id’,
`resource_name` varchar(255) DEFAULT NULL COMMENT ‘资源名称’,
`resource_url` varchar(255) DEFAULT NULL COMMENT ‘系统中的url路径’,
`resource_desc` varchar(255) DEFAULT NULL COMMENT ‘资源描述’,
`status` int(5) DEFAULT ‘1’ COMMENT ‘状态 1.启用 2.废弃’,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`resource_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=’资源表’;

④资源角色表

CREATE TABLE `oauth_role_resource` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`role_id` bigint(20) DEFAULT NULL COMMENT ‘角色id’,
`resource_id` bigint(20) DEFAULT NULL COMMENT ‘资源id’,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=’角色和资源中间表’;

⑤角色表

CREATE TABLE `oauth_access_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘id’,
`role_name` varchar(20) DEFAULT NULL COMMENT ‘角色名称’,
`role_type` tinyint(2) DEFAULT ‘-1’ COMMENT ‘角色类型 0:超级管理员 1:运营 2:财务 3:技术 4:BD’,
`role_desc` varchar(255) DEFAULT NULL COMMENT ‘角色描述’,
`status` tinyint(2) DEFAULT ‘1’ COMMENT ‘状态 1:有效 0:无效’,
`create_time` timestamp NULL DEFAULT NULL COMMENT ‘创建时间’,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ‘修改时间’,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=’系统角色表’;

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hjMTIzX2phdmE_size_16_color_FFFFFF_t_70

从这张图中可以看出,用户表和权限表,角色表有直接关系, 而资源表只能被角色表访问

2.生成token

  1. 请求参数: grantType 必传 ; 进行哪种模式鉴权, 然后根据这个值,相应从实例化工厂里面取出对应的实例化service
  2. 这样做的好处就是接口中只有一个获取token方法,但是具体的实现在各个实现类中
  3. ①去权限表查询权限范围,并且判断是否有生成这种模式的token权限
  4. ②根据用户名和密码去用户服务获取用户基本信息,校验用户密码
  5. 获取用户的能访问的资源信息
  6. 根据JWT 将用户信息进行编码生成token,并且保存到redis里面

3.校验token

在网关中获取访问接口的token,在redis里面找到对应token,并且没失效, 解析token,获取用户信息资源信息,如果不完全信任,

找到封装信息中的资源信息,和访问URL对比,从而决定放行还是拦截

  1. 但是这种方式如果资源信息比较多的话,生成token过大,建议去查询资源角色表,从而决定是否放行

发表评论

表情:
评论列表 (有 0 条评论,21人围观)

还没有评论,来说两句吧...

相关阅读