基于 spring-security-oauth2 实现 oauth2 数据库版
文章代码地址:链接描述可以下载直接运行,基于 springboot2.1.5,springcloud Greenwich 版本实现
该系列分为两个部分:分为内存实现,数据库实现。其中数据库实现采用 RBAC 权限角色管理。
上一篇,介绍了 oauth2 的内存实现,也就是认证服务把客户端和用户信息都存储在内存中,这样不利于拓展,不适合于生产环境。下面,我们开始基于 mysql 数据库的 oauth2 实现。
首先,我们创建 oauth2 数据库,注意编码选择 utf-8mb4 格式,utf- 8 是不规范的,mysql 也没有进行更改。
好了,现在我们初始化表,sql 如下:
Drop table if exists oauth_client_details;
create table oauth_client_details (
client_id VARCHAR(255) PRIMARY KEY,
resource_ids VARCHAR(255),
client_secret VARCHAR(255),
scope VARCHAR(255),
authorized_grant_types VARCHAR(255),
web_server_redirect_uri VARCHAR(255),
authorities VARCHAR(255),
access_token_validity INTEGER,
refresh_token_validity INTEGER,
additional_information TEXT,
autoapprove VARCHAR (255) default ‘false’
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Drop table if exists oauth_access_token;
create table oauth_access_token (
token_id VARCHAR(255),
token BLOB,
authentication_id VARCHAR(255),
user_name VARCHAR(255),
client_id VARCHAR(255),
authentication BLOB,
refresh_token VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Drop table if exists oauth_refresh_token;
create table oauth_refresh_token (
token_id VARCHAR(255),
token BLOB,
authentication BLOB
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Drop table if exists oauth_code;
create table oauth_code (
code VARCHAR(255),
authentication BLOB
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
— Add indexes
create index token_id_index on oauth_access_token (token_id);
create index authentication_id_index on oauth_access_token (authentication_id);
create index user_name_index on oauth_access_token (user_name);
create index client_id_index on oauth_access_token (client_id);
create index refresh_token_index on oauth_access_token (refresh_token);
create index token_id_index on oauth_refresh_token (token_id);
create index code_index on oauth_code (code);
— INSERT DEFAULT DATA
INSERT INTO oauth_client_details
VALUES (‘dev’, ”, ‘dev’, ‘app’, ‘authorization_code’, ‘http://localhost:7777/’, ”, ‘3600’, ‘3600’, ‘{“country”:”CN”,”country_code”:”086″}’, ‘TAIJI’);
— —————————-
— Table structure for tb_user
— —————————-
DROP TABLE IF EXISTS tb_user
;
CREATE TABLE tb_user
(
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
`username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名',
`password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
`gender` int(2) DEFAULT NULL COMMENT '性别(1 男 2 女)',
`email` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '邮箱',
`create_time` datetime DEFAULT NULL COMMENT '用户创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`removed` int(2) DEFAULT NULL COMMENT '是否删除(1 删除 0 未删除)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
— —————————-
— Records of tb_user
— —————————-
BEGIN;
INSERT INTO tb_user
VALUES (1, ‘admin’, ‘$2a$10$vWyL7fMGQRvVNn.i2bK40e3z30Nem4k.ElwuxdLBNzKFxRCcXCoqm’, 1, NULL, ‘2019-05-30 15:53:45’, ‘2019-05-30 15:53:51’, 0);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
— —————————-
— Table structure for tb_user_role
— —————————-
DROP TABLE IF EXISTS tb_user_role
;
CREATE TABLE tb_user_role
(
`id` bigint(11) NOT NULL COMMENT '主键 ID',
`user_id` bigint(11) DEFAULT NULL COMMENT '用户主键',
`role_id` bigint(11) DEFAULT NULL COMMENT '角色 ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
— —————————-
— Records of tb_user_role
— —————————-
BEGIN;
INSERT INTO tb_user_role
VALUES (1, 1, 1);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
— —————————-
— Table structure for tb_role
— —————————-
DROP TABLE IF EXISTS tb_role
;
CREATE TABLE tb_role
(
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
`parent_id` bigint(20) DEFAULT NULL COMMENT '父类 ID',
`name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '角色名字',
`ename` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '角色名字',
`description` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '描述',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
— —————————-
— Records of tb_role
— —————————-
BEGIN;
INSERT INTO tb_role
VALUES (1, 0, ‘ 超级管理员 ’, ‘ADMIN’, NULL, ‘2019-05-30 16:09:53’, ‘2019-05-30 16:09:57’);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
— —————————-
— Table structure for tb_role_permission
— —————————-
DROP TABLE IF EXISTS tb_role_permission
;
CREATE TABLE tb_role_permission
(
`id` bigint(11) NOT NULL COMMENT '主键 ID',
`role_id` bigint(11) DEFAULT NULL COMMENT '角色 ID',
`permission_id` bigint(11) DEFAULT NULL COMMENT '权限 ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
— —————————-
— Records of tb_role_permission
— —————————-
BEGIN;
INSERT INTO tb_role_permission
VALUES (1, 1, 1);
INSERT INTO tb_role_permission
VALUES (2, 1, 2);
INSERT INTO tb_role_permission
VALUES (3, 1, 3);
INSERT INTO tb_role_permission
VALUES (4, 1, 4);
INSERT INTO tb_role_permission
VALUES (5, 1, 5);
INSERT INTO tb_role_permission
VALUES (6, 1, 6);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
— —————————-
— Table structure for tb_permission
— —————————-
DROP TABLE IF EXISTS tb_permission
;
CREATE TABLE tb_permission
(
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
`parent_id` bigint(11) DEFAULT NULL COMMENT '用户 ID',
`name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '权限名字',
`ename` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '权限名字',
`url` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '请求路径',
`description` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '描述',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
— —————————-
— Records of tb_permission
— —————————-
BEGIN;
INSERT INTO tb_permission
VALUES (1, 0, ‘ 系统管理 ’, ‘System’, ‘/’, NULL, ‘2019-05-30 16:22:20’, ‘2019-05-30 16:22:24’);
INSERT INTO tb_permission
VALUES (2, 0, ‘ 用户管理 ’, ‘SystemUser’, ‘/users’, NULL, ‘2019-05-30 16:23:28’, ‘2019-05-30 16:23:32’);
INSERT INTO tb_permission
VALUES (3, 0, ‘ 查看用户 ’, ‘SystemUserView’, NULL, NULL, ‘2019-05-30 16:24:29’, ‘2019-05-30 16:24:33’);
INSERT INTO tb_permission
VALUES (4, 0, ‘ 新增用户 ’, ‘SystemUserInsert’, NULL, NULL, ‘2019-05-30 16:25:09’, ‘2019-05-30 16:25:13’);
INSERT INTO tb_permission
VALUES (5, 0, ‘ 编辑用户 ’, ‘SystemUserUpdate’, NULL, NULL, ‘2019-05-30 16:25:53’, ‘2019-05-30 16:25:57’);
INSERT INTO tb_permission
VALUES (6, 0, ‘ 删除用户 ’, ‘SystemUserDelete’, NULL, NULL, ‘2019-05-30 16:26:49’, ‘2019-05-30 16:26:54’);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
我们看看表结构:
简单介绍,这是把客户端配置从内存中转移到 oauth_client_details 表中,字段意思请参考上一篇链接描述
oauth_access_token: access_token 表结构:
oauth_code 表结构:
oauth_refresh_token 表结构:
下面是用户信息表:
tb_user 表:
tb_user_role 表结构:
tb_role 表结构:
tb_role_permission 表结构:
tb_permission 表结构:
好了,表设计完成。下面我们开始编码:
(1)我们把之前的项目复制一份修改名字,添加依赖:
我们添加数据库的依赖,使用 mybatis 作为持久层框架。
(2)下面是项目结构:
这里介绍 intellij 的 mybatis 自动生成插件 easycode,只要配置好数据库连接,可以自动生成 domain,mapper,xml 等文件。
首先,修改 WebSecurityConfig 文件如下:
这里将内存换到数据库,使用 userDetailsService,因为,我们需要注入 UserDetailsService, 创建 UserDetailsServiceImpl 文件
这里实现 UserDetailsService 接口,实现 loadUserByUsername 方法,这个方法根据用户名查询用户信息,查询用户权限,返回认证用户 import org.springframework.security.core.userdetails.User; userdetails 包下的 User 对象。
这里重点介绍一下查询权限的 sql:
通过连表用户,角色,权限等连表查询权限。
(3)用户验证完成,开始认证处理,修改 AuthConfig 如下:
这里我们将客户端 client 放到数据库,使用 JdbcClientDetailsService。创建 service 的时候,需要使用 DataSource 数据源,从数据库查询。使用 jdbcTokenStore 存储 token。
(4)创建 OauthPasswordConfig 配置注入 BCrytpPasswordEncoder 对象:
(5)实体类如下:
(6)应用配置文件:
(7)完成,现在我们使用 9001 端口启动应用:
(8)启动成功,我们访问地址:
http://localhost:9001/oauth/oauthorize?client_id=client&response_type=code/
如下:
输入账户:admin 密码:123456 点击登录:
同意授权
跳转成功,我们使用 code,访问这个地址, 获取 token
http://client:secret@http://localhost:9001/oauth/token
得到结果:
成功,得到 access_token。
基于数据库的认证服务完成。未完待续,下一篇介绍资源服务器和认证服务器的集成。
有问题,请留言。