From 3ec6015300cba275e56e28e61f7c059a5ac8ab5a Mon Sep 17 00:00:00 2001 From: zhuyijun Date: Thu, 18 Aug 2022 01:24:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=95=B0=E6=8D=AE=E5=BA=93sq?= =?UTF-8?q?l?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/zyjblogs_rbac.sql | 88 ++++++++++++++----- .../AuthorizationServerConfiguration.java | 53 ++++++----- .../oauth/config/security/TokenConfig.java | 19 +++- .../security/WebSecurityConfiguration.java | 7 +- .../cn/zyjblogs/rbac/RbacApplication.java | 3 + .../config/resource/ResourceServerConfig.java | 18 ++-- .../rbac/config/security/TokenConfig.java | 31 +++++++ 7 files changed, 158 insertions(+), 61 deletions(-) create mode 100644 zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/security/TokenConfig.java diff --git a/db/zyjblogs_rbac.sql b/db/zyjblogs_rbac.sql index 53c0ddf..5b534b6 100644 --- a/db/zyjblogs_rbac.sql +++ b/db/zyjblogs_rbac.sql @@ -16,29 +16,75 @@ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; +-- +-- Oauth sql -- MYSQL +-- --- ---------------------------- --- Table structure for oauth_client_details --- ---------------------------- -DROP TABLE IF EXISTS `oauth_client_details`; -CREATE TABLE `oauth_client_details` ( - `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户端id', - `resource_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '资源id集合', - `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '客户端密钥', - `scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '客户端申请的权限范围,可选值包括read,\r\n write等', - `authorized_grant_types` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '客户端支持的grant_type,\r\n 可选值包括authorization_code, password, refresh_token, implicit, client_credentials, 若支持多个grant_type用逗号, 分隔', - `web_server_redirect_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '客户端的重定向URI,\r\n 可为空, 当grant_type为authorization_code或implicit时, 在Oauth的流程中会使用并检查与注册时填写的redirect_uri是否一致.', - `authorities` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT ' 指定客户端所拥有的Spring Security的权限值,\r\n 可选, 若有多个权限值, 用逗号, 分隔, 如: ROLE_UNITY, ROLE_USER', - `access_token_validity` int(11) NULL DEFAULT NULL COMMENT '设定客户端的access_token的有效时间值(单位:秒)', - `refresh_token_validity` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '设定客户端的refresh_token的有效时间值(单位:秒)', - `additional_information` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '其他信息, JSON格式', - `autoapprove` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户是否自动Approval操作,\r\n 默认值为 \'\' false \'\', 可选值 true, false', - PRIMARY KEY (`client_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'oauth2 client表' ROW_FORMAT = Dynamic; +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, + create_time timestamp default now(), + archived tinyint(1) default '0', + trusted tinyint(1) default '0', + autoapprove VARCHAR (255) default 'false' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- ---------------------------- --- Records of oauth_client_details --- ---------------------------- + +Drop table if exists oauth_access_token; +create table oauth_access_token ( + create_time timestamp default now(), + token_id VARCHAR(255), + token BLOB, + authentication_id VARCHAR(255) UNIQUE, + 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 ( + create_time timestamp default now(), + token_id VARCHAR(255), + token BLOB, + authentication BLOB +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +Drop table if exists oauth_code; +create table oauth_code ( + create_time timestamp default now(), + 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 INTO zyjblogs_rbac.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, autoapprove, trusted, archived) +VALUES('zyjblogs-rbac', 'zyjblogs-rbac', '$2a$10$Wk2w4OX5DpFgG3rBuhPnnulCSOIuU3TZhpWjaOq39LZnL.p0LJila', 'all', 'authorization_code,password,client_credentials,implicit,refresh_token', NULL, NULL, NULL, NULL, NULL, 'false', NULL, NULL); -- zyjblogs_rbac.`user` definition DROP TABLE IF EXISTS `user`; diff --git a/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/AuthorizationServerConfiguration.java b/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/AuthorizationServerConfiguration.java index 8146e80..6758d68 100644 --- a/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/AuthorizationServerConfiguration.java +++ b/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/AuthorizationServerConfiguration.java @@ -6,6 +6,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; @@ -14,11 +15,19 @@ import org.springframework.security.oauth2.config.annotation.web.configurers.Aut import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices; +import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices; +import org.springframework.security.oauth2.provider.token.AccessTokenConverter; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; +import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; + +import javax.sql.DataSource; +import java.util.List; /** * @author zhuyijun @@ -31,9 +40,10 @@ import org.springframework.security.oauth2.provider.token.TokenStore; @RequiredArgsConstructor public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { private final TokenStore tokenStore; - private final ClientDetailsService clientDetailsService; private final AuthenticationManager authenticationManager; - + private final JwtAccessTokenConverter accessTokenConverter; + private final PasswordEncoder passwordEncoder; + private final DataSource dataSource; /** * 令牌端点的安全约束 * @@ -61,23 +71,7 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - clients - //存储方式 - .inMemory() - //客户端id client_id - .withClient("zyjblogs-rbac") - //secret - .secret(new BCryptPasswordEncoder().encode("secret")) - //资源列表 - .resourceIds("zyjblogs-rbac") - .authorizedGrantTypes("authorization_code", - "password", "client_credentials", "implicit", "refresh_token") - //允许授权封范围 - .scopes("all") - // - .autoApprove(false) - //加上验证回调地址 - .redirectUris("https://www.baidu.com"); + clients.withClientDetails(clientDetails(dataSource)); } /*** @@ -93,7 +87,7 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu //密码模式 authenticationManager(authenticationManager) //授权码模式 - .authorizationCodeServices(authorizationCodeServices()) + .authorizationCodeServices(authorizationCodeServices(dataSource)) .tokenServices(tokenServices()) //允许表单认证 .allowedTokenEndpointRequestMethods(HttpMethod.POST); @@ -107,19 +101,32 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu public AuthorizationServerTokenServices tokenServices(){ DefaultTokenServices tokenServices = new DefaultTokenServices(); //客户端信息服务 - tokenServices.setClientDetailsService(clientDetailsService); + tokenServices.setClientDetailsService(clientDetails(dataSource)); + //是否产生刷新令牌 tokenServices.setSupportRefreshToken(true); //令牌储存策略 tokenServices.setTokenStore(tokenStore); + tokenServices.setTokenEnhancer(accessTokenConverter); + //令牌默认有效期 tokenServices.setAccessTokenValiditySeconds(7200); //刷新令牌默认有效期3天 tokenServices.setRefreshTokenValiditySeconds(259200); + return tokenServices; } + @Bean - public AuthorizationCodeServices authorizationCodeServices(){ - return new InMemoryAuthorizationCodeServices(); + public ClientDetailsService clientDetails(DataSource dataSource){ + JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource); + jdbcClientDetailsService.setPasswordEncoder(passwordEncoder); + return jdbcClientDetailsService; } + @Bean + public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource){ + //设置授权码模式的授权码如何存取 + return new JdbcAuthorizationCodeServices(dataSource); + } + } \ No newline at end of file diff --git a/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/TokenConfig.java b/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/TokenConfig.java index c189de1..a2e80d3 100644 --- a/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/TokenConfig.java +++ b/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/TokenConfig.java @@ -4,16 +4,29 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; /** * @author zhuyijun */ @Configuration public class TokenConfig { - //令牌存储策略 + private String SIGNING_KEY="zyjblogs123"; + /** + * 令牌存储策略 + * @return + */ @Bean public TokenStore tokenStore(){ - //内存方式,生成普通令牌 - return new InMemoryTokenStore(); + //JWT令牌存储方案 + return new JwtTokenStore(accessTokenConverter()); + } + + @Bean + public JwtAccessTokenConverter accessTokenConverter(){ + JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); + converter.setSigningKey(SIGNING_KEY); + return converter; } } diff --git a/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/WebSecurityConfiguration.java b/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/WebSecurityConfiguration.java index e3da717..c022ec7 100644 --- a/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/WebSecurityConfiguration.java +++ b/zyjblogs-oauth/src/main/java/cn/zyjblogs/oauth/config/security/WebSecurityConfiguration.java @@ -10,6 +10,12 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; +import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; +import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices; + +import javax.sql.DataSource; @Configuration @EnableWebSecurity @@ -25,7 +31,6 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { return new BCryptPasswordEncoder(); } - /** * 认证管理器 * @param diff --git a/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/RbacApplication.java b/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/RbacApplication.java index 36b180b..f2f4da4 100644 --- a/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/RbacApplication.java +++ b/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/RbacApplication.java @@ -19,6 +19,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @SpringBootApplication public class RbacApplication { public static void main(String[] args) { + BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); + + System.out.println(bCryptPasswordEncoder.encode("secret")); SpringApplication.run(RbacApplication.class, args); } } diff --git a/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/resource/ResourceServerConfig.java b/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/resource/ResourceServerConfig.java index 2fc48a8..85630be 100644 --- a/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/resource/ResourceServerConfig.java +++ b/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/resource/ResourceServerConfig.java @@ -1,5 +1,6 @@ package cn.zyjblogs.rbac.config.resource; +import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -9,6 +10,7 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.RemoteTokenServices; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; +import org.springframework.security.oauth2.provider.token.TokenStore; /** * 资源服务 @@ -16,17 +18,16 @@ import org.springframework.security.oauth2.provider.token.ResourceServerTokenSer */ @Configuration @EnableResourceServer +@RequiredArgsConstructor public class ResourceServerConfig extends ResourceServerConfigurerAdapter { private static final String RESOURCE_ID="zyjblogs-rbac"; - public ResourceServerConfig() { - super(); - } + private final TokenStore tokenStore; @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId(RESOURCE_ID) // 验证令牌的服务 - .tokenServices(tokenServices()) + .tokenStore(tokenStore) .stateless(true); } @@ -40,14 +41,5 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter { .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } - - @Bean - public ResourceServerTokenServices tokenServices(){ - RemoteTokenServices services = new RemoteTokenServices() ; - services.setCheckTokenEndpointUrl("http://127.0.0.1:9029/oauth/check_token"); - services.setClientId(RESOURCE_ID); - services.setClientSecret("secret"); - return services; - } } diff --git a/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/security/TokenConfig.java b/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/security/TokenConfig.java new file mode 100644 index 0000000..223d143 --- /dev/null +++ b/zyjblogs-rbac/src/main/java/cn/zyjblogs/rbac/config/security/TokenConfig.java @@ -0,0 +1,31 @@ +package cn.zyjblogs.rbac.config.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; + +/** + * @author zhuyijun + */ +@Configuration +public class TokenConfig { + private String SIGNING_KEY="zyjblogs123"; + /** + * 令牌存储策略 + * @return + */ + @Bean + public TokenStore tokenStore(){ + //JWT令牌存储方案 + return new JwtTokenStore(accessTokenConverter()); + } + + @Bean + public JwtAccessTokenConverter accessTokenConverter(){ + JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); + converter.setSigningKey(SIGNING_KEY); + return converter; + } +}