# oauth **Repository Path**: zhou_jm/oauth ## Basic Information - **Project Name**: oauth - **Description**: oauth2+jwt+gateway实现统一身份认证和鉴权 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2022-06-12 - **Last Updated**: 2025-09-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Cloud Gateway+springsecurity-Oauth2+JWT实现统一认证和鉴权 ## 1. JWT ### 1.1 生成jwt密钥文件 本项目采用JWT令牌生成采用非对称加密算法。 可以使用idea的Terminal控制台输入相关命令生成: ~~~bash keytool -genkeypair -alias oauth -keyalg RSA -keypass 420188 -keystore oauth.jks -storepass 420188 ~~~ ~~~tex 解释: -alias:密钥的别名 -keyalg:使用的hash算法 -keypass:密钥的访问密码(文件内容的读取密钥) -keystore:密钥库文件名,macrosoft.jks保存了生成的证书 -storepass:密钥库的访问密码(即读取文件的密钥) ~~~ 这样会生成一个密钥对的文件叫 oauth.jks,它供认证服务器使用。如下图: ![oauth_1.png](./images/oauth_1.png) ### 1.2 获取公钥 在生成oauth.jks文件目录下运行以下命令,输入文件密码,然后会生成公钥信息。会输入密钥库密码,即上面的storepass。 生成了公钥, 特别注意生成的公钥最后一个 - 但实际上是5个粘的时候要加上。即:从-----BEGIN 开始到END PUBLIC KEY----- 结束。把它粘贴到一行,放入public.key文件,并粘到资源服务器的resource目录下,和面好使用。 ~~~bash keytool -list -rfc --keystore oauth.jks | openssl x509 -inform pem -pubkey ~~~ 如下图: ![oauth_2.png](./images/oauth_2.png) 原理:认证服务器在生成token时会用到密钥对文件,即这里的 oauth.jks,资源服务器|网关服务器在解密的时候会用到公钥,即自己放入公钥的public.key文件。私钥加密,公钥解密。 ### 2. sql文件准备 ~~~sql /* Navicat Premium Data Transfer Source Server : tx_175.178.190.189 Source Server Type : MySQL Source Server Version : 50726 Source Host : 175.178.190.189:3306 Source Schema : oauth2_db Target Server Type : MySQL Target Server Version : 50726 File Encoding : 65001 Date: 13/06/2022 12:24:28 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for oauth_client_details -- ---------------------------- DROP TABLE IF EXISTS `oauth_client_details`; CREATE TABLE `oauth_client_details` ( `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端标 识', `resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '接入资源列表', `client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '客户端秘钥', `scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `access_token_validity` int(11) NULL DEFAULT NULL, `refresh_token_validity` int(11) NULL DEFAULT NULL, `additional_information` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL, `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0), `archived` tinyint(4) NULL DEFAULT NULL, `trusted` tinyint(4) NULL DEFAULT NULL, `autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`client_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '接入客户端信息' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of oauth_client_details -- ---------------------------- INSERT INTO `oauth_client_details` VALUES ('client_1', 'res1,res2,res3', '$2a$10$Z4JmQqdlTapnUrd7ST506uxtzdao1RBXXKitXWZo3TPsfTAoG7uv2', 'all', 'password,authorization_code,refresh_token', 'http://localhost:9401/v2/bb', NULL, NULL, NULL, NULL, '2022-06-11 17:35:45', NULL, NULL, NULL); INSERT INTO oauth2_db.oauth_client_details (client_id, resource_ids, client_secret, `scope`, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, create_time, archived, trusted, autoapprove) VALUES('client_2', 'res1,res2,res3', '$2a$10$fLACkRNJ0tY0ud.dECPsVOh6o6.Pr9Xk3hoHqab2ruw3T7Ozyz64e', 'all', 'password,authorization_code,refresh_token,client_credentials', 'http://127.0.0.1:9401/oauth/code', NULL, NULL, NULL, NULL, '2024-01-03 06:38:36.0', NULL, NULL, NULL); INSERT INTO oauth2_db.oauth_client_details (client_id, resource_ids, client_secret, `scope`, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, create_time, archived, trusted, autoapprove) VALUES('client_3', 'res1,res2,res3', '$2a$10$tUo3JaFbKw4PHi4217dTm.6tBT8.2LXw92Ffzso8YWBTbLtABSrHO', 'all', 'password,authorization_code,refresh_token,client_credentials', 'http://127.0.0.1:9201/oauth/code', NULL, NULL, NULL, NULL, '2024-01-03 05:49:02.0', NULL, NULL, NULL); -- oauth2_db.oauth_access_token definition CREATE TABLE `oauth_access_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication_id` varchar(128) NOT NULL, `user_name` varchar(256) DEFAULT NULL, `client_id` varchar(256) DEFAULT NULL, `authentication` blob, `refresh_token` varchar(256) DEFAULT NULL, PRIMARY KEY (`authentication_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- oauth2_db.oauth_approvals definition CREATE TABLE `oauth_approvals` ( `userId` varchar(256) DEFAULT NULL COMMENT '登录的用户名', `clientId` varchar(256) DEFAULT NULL COMMENT '客户端ID', `scope` varchar(256) DEFAULT NULL COMMENT '申请的权限', `status` varchar(10) DEFAULT NULL COMMENT '状态(Approve或Deny)', `expiresAt` datetime DEFAULT NULL COMMENT '过期时间', `lastModifiedAt` datetime DEFAULT NULL COMMENT '最终修改时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='授权记录'; -- oauth2_db.oauth_client_token definition CREATE TABLE `oauth_client_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication_id` varchar(128) NOT NULL, `user_name` varchar(256) DEFAULT NULL, `client_id` varchar(256) DEFAULT NULL, PRIMARY KEY (`authentication_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for oauth_code -- ---------------------------- DROP TABLE IF EXISTS `oauth_code`; CREATE TABLE `oauth_code` ( `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `authentication` blob NULL ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of oauth_code -- ---------------------------- -- oauth2_db.oauth_refresh_token definition CREATE TABLE `oauth_refresh_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication` blob ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for sys_permission -- ---------------------------- DROP TABLE IF EXISTS `sys_permission`; CREATE TABLE `sys_permission` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `permission_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限code', `permission_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限名', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_permission -- ---------------------------- INSERT INTO `sys_permission` VALUES (1, 'ADMIN', 'ADMIN'); INSERT INTO `sys_permission` VALUES (2, 'USER', 'USER'); -- ---------------------------- -- Table structure for sys_request_path -- ---------------------------- DROP TABLE IF EXISTS `sys_request_path`; CREATE TABLE `sys_request_path` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `url` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '请求路径', `description` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '路径描述', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '请求路径' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_request_path -- ---------------------------- INSERT INTO `sys_request_path` VALUES (1, '/order/add', '订单新增'); INSERT INTO `sys_request_path` VALUES (2, '/order/delete', '订单删除'); INSERT INTO `sys_request_path` VALUES (3, '/order/update', '订单更新'); INSERT INTO `sys_request_path` VALUES (4, '/order/query', '订单查询'); -- ---------------------------- -- Table structure for sys_request_path_permission_relation -- ---------------------------- DROP TABLE IF EXISTS `sys_request_path_permission_relation`; CREATE TABLE `sys_request_path_permission_relation` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `url_id` int(11) NULL DEFAULT NULL COMMENT '请求路径id', `permission_id` int(11) NULL DEFAULT NULL COMMENT '权限id', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '路径权限关联表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_request_path_permission_relation -- ---------------------------- INSERT INTO `sys_request_path_permission_relation` VALUES (1, 1, 1); INSERT INTO `sys_request_path_permission_relation` VALUES (2, 2, 1); INSERT INTO `sys_request_path_permission_relation` VALUES (3, 3, 1); INSERT INTO `sys_request_path_permission_relation` VALUES (4, 4, 1); INSERT INTO `sys_request_path_permission_relation` VALUES (5, 4, 2); -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `role_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名', `role_description` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色说明', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户角色表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_role -- ---------------------------- INSERT INTO `sys_role` VALUES (1, 'admin', '管理员角色'); INSERT INTO `sys_role` VALUES (2, 'user', '普通用户角色'); -- ---------------------------- -- Table structure for sys_role_permission_relation -- ---------------------------- DROP TABLE IF EXISTS `sys_role_permission_relation`; CREATE TABLE `sys_role_permission_relation` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `role_id` int(11) NULL DEFAULT NULL COMMENT '角色id', `permission_id` int(11) NULL DEFAULT NULL COMMENT '权限id', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色-权限关联关系表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_role_permission_relation -- ---------------------------- INSERT INTO `sys_role_permission_relation` VALUES (1, 1, 1); INSERT INTO `sys_role_permission_relation` VALUES (2, 2, 2); -- ---------------------------- -- Table structure for sys_user -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `account` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '账号', `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名', `password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户密码', `last_login_time` datetime(0) NULL DEFAULT NULL COMMENT '上一次登录时间', `enabled` tinyint(1) NULL DEFAULT 1 COMMENT '账号是否可用。默认为1(可用)', `not_expired` tinyint(1) NULL DEFAULT 1 COMMENT '是否过期。默认为1(没有过期)', `account_not_locked` tinyint(1) NULL DEFAULT 1 COMMENT '账号是否锁定。默认为1(没有锁定)', `credentials_not_expired` tinyint(1) NULL DEFAULT 1 COMMENT '证书(密码)是否过期。默认为1(没有过期)', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间', `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人', `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `user_name`(`user_name`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1507224801909940227 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_user -- ---------------------------- INSERT INTO `sys_user` VALUES (1, 'admin', 'admin', '$2a$10$Z4JmQqdlTapnUrd7ST506uxtzdao1RBXXKitXWZo3TPsfTAoG7uv2', '2022-06-06 17:26:19', 1, 1, 1, 1, NULL, NULL, NULL, NULL); INSERT INTO `sys_user` VALUES (1507224801909940226, 'zjm', 'zjm', '$2a$10$kc9MMHhNzmXruiH755wnO.5GrW5nR02cEWkkqagvhXeVfhZPhGuZu', '2022-06-06 17:26:19', 1, 1, 1, 1, NULL, NULL, NULL, NULL); -- ---------------------------- -- Table structure for sys_user_role_relation -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role_relation`; CREATE TABLE `sys_user_role_relation` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id', `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色id', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1507224802006409220 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户角色关联关系表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of sys_user_role_relation -- ---------------------------- INSERT INTO `sys_user_role_relation` VALUES (1507224802006409218, 1, 1); INSERT INTO `sys_user_role_relation` VALUES (1507224802006409219, 1507224801909940226, 2); SET FOREIGN_KEY_CHECKS = 1; ~~~ oauth_client_details、oauth_code为oauth2框架用到的表。 oauth_client_details:配置客户端信息(客户端id和客户端密码—客户端、授权码、密码模式都需要用到)、socpe(授权范围)、authorized_grant_types(授权模式—常用有authorization-code、password、client credentials、refresh_token) * 注意:客户端模式(client credentials)没有refresh_token,使用该模式不会返回refresh_token,只有access_token。 以下是自定义表: sys_permission:权限表 sys_request_path:请求路径 sys_request_path_permission_relation:路径权限关联表 sys_role:用户角色表 sys_role_permission_relation:角色-权限关联关系表 sys_user:用户表 sys_user_role_relation:用户角色关联关系表 数据库关系图: ​ ![oauth_4.jpg](./images/oauth_4.jpg) ### 3.认证流程图 ![oauth_3.png](./images/oauth_3.png) 这里的认证服务就是oauth-auth,网关就是我的oauth-gateway,其他的都可以成为资源服务。 ### 4. 项目完善 #### 4.1 安全性 ##### 4.1.1 资源服务器获取用户信息 由于目前是在微服务网关解析了token获取当前登录用户信息,然后将用户信息放到请求头中,接着调用资源服务器,有可能会被抓包从而获取到用户信息,从而引发用户信息泄露问题。 解决办法:不在网关中解析token,放在资源服务器解析token获取用户信息? #### 4.2 其他 ##### 4.2.1 token回收问题 由于目前用户登录获取token后,只能等到token过期该token才为非法token,在这个期间如果用户重新登录,没有及时回收旧token信息。 解决办法:可以采用redis缓存token,当有新的token时替换掉旧的token,验证的时候验证最新的token,其他都为非法token。 ##### 4.2.2 令牌桶算法限流 了解令牌桶限流。 ##### 4.2.3 认证服务器与资源服务器的resource_id和scope用法 ~~~tex ResourceID当然是在Resource Server资源服务器进行验证(你能不能访问我的资源,当然由我自己来验证)。 当资源请求发送到Resource Server的时候会携带access_token,Resource Server会根据access_token找到client_id, 进而找到该client可以访问的resource_ids。如果resource_ids包含ResourceServer自己设置ResourceID,这关就过去了,就可以继续进行其他的权限验证 在表:oauth_client_details的字段resource_ids可以配置多个资源名,表示当前这个clientId可以访问多个资源服务。例如:res1,res2 注意: 客户端在登录时可以传入clientId、clientSecret(线下给到客户端),那么这样就可以在oauth_client_details配置该clientId的访问资源服务器了,即resouce_ids的值 这里目(登录)前写死只有一个clientId、clientSecret(即c1和secret1),在oauth_client_details表中配置了c1对应的resource_ids字段的res1,res2,res3 也就是说资源服务器标识为res1或res2或res3的,clientId为c1的登录账号皆可访问 ~~~ 注意:这里资源服务器不仅仅是通过RESOURCE_ID来控制访问权限, 还通过scope来控制: ~~~java @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/**") .access("#oauth2.hasScope('ROLE_USER')") .and().csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } ~~~ 在oauth_client_details中对应的clientId、clientSecret对应的数据的字段scope必须包含当前资源服务器中的#oauth2.hasScope(‘ROLE_USER’)配置才能访问