为什么自己实现oauth2.0?

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

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

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

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

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

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

    整个鉴权中心一共五张表:

    ①权限表:

CREATE TABLE `oauth_access_info` (
       `access_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '权限id',
       `client_id` varchar(100) DEFAULT NULL COMMENT '客户端id',
       `user_id` varchar(100) DEFAULT NULL COMMENT '用户id',
      `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中申请微信登录,然后跳转到微信登录页面

                     用户输入完微信用户名和密码并且携带者APP跳转网页,请求微信服务器,微信服务器分配一个code,

                    然后重定向到那个APP页面,APP页面拿到code,去请求APP后台服务,后台服务拿着code,去请求微信获取token,

                    然后就可以拿着这个token,获取用户微信数据了

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

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

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

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

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 : 因为有可能一个客户端,可同时进行两种鉴权的,

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

这个表因为经常访问,我现在是把他放在了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='系统角色表';

 

springcloud 集成oauth2 oauth2.0 springcloud_拦截器

 

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

 

2.生成token

    请求参数:  grantType 必传 ; 进行哪种模式鉴权, 然后根据这个值,相应从实例化工厂里面取出对应的实例化service类

     这样做的好处就是接口中只有一个获取token方法,但是具体的实现在各个实现类中

    ①去权限表查询权限范围,并且判断是否有生成这种模式的token权限

    ②根据用户名和密码去用户服务获取用户基本信息,校验用户密码

    ③ 获取用户的能访问的资源信息

    ④ 根据JWT 将用户信息进行编码生成token,并且保存到redis里面

3.校验token

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

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

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