springsecurity-oauth2之基础知识介绍(一)
1.公钥与私钥
本项目采用JWT令牌生成采用非对称加密算法。
1.1 自己电脑上安装 Win64OpenSSL-1_1_1b.exe
1.2 找一个文件夹使用cmd命令打开dos命令窗口,输入:
keytool -genkeypair -alias macrosoft -keyalg RSA -keypass 420188 -keystore macrosoft.jks -storepass 420188
解释:
-alias
:密钥的别名
-keyalg
:使用的hash算法
-keypass
:密钥的访问密码(文件内容的读取密钥)
-keystore
:密钥库文件名,macrosoft.jks保存了生成的证书
-storepass
:密钥库的访问密码(即读取文件的密钥)
这样会生成一个密钥对的文件,叫 macrosoft.jks,它供认证服务器使用,现在要获取公钥供资源服务器使用。
1.3 获取公钥
在上面macrosoft.jks所在文件夹打开dos命令窗口,输入:
keytool -list -rfc --keystore macrosoft.jks | openssl x509 -inform pem -pubkey
会输入密钥库密码,即上面的storepass。 生成了公钥, 特别注意生成的公钥最后一个 - 但实际上是5个
粘的时候要加上。即:从-----BEGIN 开始到END PUBLIC KEY----- 结束。
把它粘贴到一行,放入public.key文件,并粘到资源服务器的resource目录下,和面好使用。
原理:认证服务器在生成token时会用到密钥对文件,即这里的
macrosoft.jks,资源服务器在解密的时候会用到公钥,即自己放入公钥的public.key文件。私钥加密,公钥解密。
2.关于资源服务器的认证
2.1 资源服务器的配置
资源服务器通过:RESOURCE_ID 和 scope来限制当前请求是否能访问本服务的。 Spring Security OAuth2
架构上分为Authorization Server认证服务器和Resource Server资源服务器。 我们可以为每一个Resource
Server(一个微服务实例)设置一个resourceid。Authorization Server给client第三方客户端授权的时候,
可以设置这个client可以访问哪一些Resource Server资源服务,如果没设置,就是对所有的Resource
Server都有访问权限。
在每个ResourceServer实例上设置resourceId,该resourceId作为该服务资源的唯一标识。(假如同一个微服务资源部署多份,resourceId相同)
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {
private static final String DEMO_RESOURCE_ID = "res1";
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(DEMO_RESOURCE_ID)
//...... 还可以有有其他的配置
}
}
2.2 AuthorizationServer如何设置ResourceIDs?
在AuthorizationServer为客户端client配置ResourceID的目的是:限制某个client可以访问的资源服务
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//配置客户端存储到db 代替原来得内存模式
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
clientDetailsService.setPasswordEncoder(passwordEncoder);
登录的时候:
headers.add("Authorization", getHttpBasic(clientId, clientSecret));
//4.组装最终请求参数
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
//5.发起登录请求接口
ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);
private String getHttpBasic(String clientId, String clientSecret) {
String value = clientId + ":" + clientSecret;
byte[] encode = Base64Utils.encode(value.getBytes(StandardCharsets.UTF_8));
return "Basic " + new String(encode);
}
这里需要使用JdbcClientDetailsService类和数据库表oauth_client_details
进行配置的持久化存储,以及动态配置
2.3 ResourceID在哪验证?
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来控制:
@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’)配置才能访问
3.sql文件准备
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` bigint(0) 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(0) NULL DEFAULT NULL COMMENT '创建人',
`update_user` int(0) NULL DEFAULT NULL COMMENT '修改人',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `user_name`(`user_name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1507224801909940226 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `sys_user_role_relation`;
CREATE TABLE `sys_user_role_relation` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`user_id` bigint(0) NULL DEFAULT NULL COMMENT '用户id',
`role_id` bigint(0) NULL DEFAULT NULL COMMENT '角色id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1507224802006409218 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户角色关联关系表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `sys_role_permission_relation`;
CREATE TABLE `sys_role_permission_relation` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`role_id` int(0) NULL DEFAULT NULL COMMENT '角色id',
`permission_id` int(0) NULL DEFAULT NULL COMMENT '权限id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色-权限关联关系表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` bigint(0) 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 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户角色表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `sys_request_path_permission_relation`;
CREATE TABLE `sys_request_path_permission_relation` (
`id` bigint(0) NULL DEFAULT NULL COMMENT '主键id',
`url_id` int(0) NULL DEFAULT NULL COMMENT '请求路径id',
`permission_id` int(0) NULL DEFAULT NULL COMMENT '权限id'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '路径权限关联表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `sys_request_path`;
CREATE TABLE `sys_request_path` (
`id` bigint(0) 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 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '请求路径' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` bigint(0) 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 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
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;
SET FOREIGN_KEY_CHECKS = 1;
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(0) NULL DEFAULT NULL,
`refresh_token_validity` int(0) 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(0) NULL DEFAULT NULL,
`trusted` tinyint(0) 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;
SET FOREIGN_KEY_CHECKS = 1;
4.认证流程图
这里的认证服务就是我的macro-auth,网关就是我的macro-gateway,其他的都可以成为资源服务