客户端信息入库
oauth_client_details
TIP
- 为什么要入库 ??
- 配置资源服务器需要为每一个App配置一个AppID
- 优雅
- 简单
- 等等.........
之前的写法
- (这个还是只配置了一个)
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("javaboy")
.secret(new BCryptPasswordEncoder().encode("123"))
.resourceIds("res1")
.authorizedGrantTypes("authorization_code","refresh_token")
.scopes("all")
.redirectUris("http://localhost:8082/index.html");
}
- 客户端信息入库涉及到的接口主要是 ClientDetailsService,这个接口主要有两个实现类
- InMemoryClientDetailsService
- JdbcClientDetailsService
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(48) NOT NULL,
`resource_ids` varchar(256) DEFAULT NULL,
`client_secret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`authorized_grant_types` varchar(256) DEFAULT NULL,
`web_server_redirect_uri` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) DEFAULT NULL,
`autoapprove` varchar(256) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- auth-server 添加数据库依赖,和配置 application.properties
spring.datasource.url=jdbc:mysql:///ssm?useUnicode=true&characterEncoding=UTF-8&serverTimeZone=Asia/Shanghai
spring.datasource.password=0
spring.datasource.username=root
spring.main.allow-bean-definition-overriding=true
这里的配置多了最后一条。这是因为我们一会要创建自己的 ClientDetailsService,而系统已经创建了 ClientDetailsService,加了最后一条就允许我们自己的实例覆盖系统默认的实例。
- 接下来,我们来提供自己的实例即可:
@Autowired
DataSource dataSource;
@Bean
ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService());
}
配置完成后,重启 auth-server,走一遍第三方登录流程
修改后的 AuthorizationServerTokenServices 实例如下:
@Bean
AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
services.setClientDetailsService(clientDetailsService());
services.setSupportRefreshToken(true);
services.setTokenStore(tokenStore);
return services;
}
授权 URL{id=authorized-url}
基于 HttpSecurity 配置 {id=http-security}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class ResourceServerConfig {
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(customizer -> {
// 这里可以根据 下方表格 配置
// 这里可以根据 下方表格 配置
// 这里可以根据 下方表格 配置
// 其他地址:需要授权访问
// 如果需要此配置,必须要放在最后一行,否则启动项目报错
customizer.anyRequest().authenticated();
});
return http.build();
}
}
- 注意:
POST
、PUT
、PATCH
、DELETE
可能会被 CSRF 拦截而响应 401, 请参考:CSRF 跨站请求伪造 mvcMatchers
基于org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher
实现,方法支持正则表达式,可以填写多个路径regexMatchers
基于org.springframework.security.web.util.matcher.RegexRequestMatcher
实现,方法支持正则表达式,可以填写多个路径antMatchers
基于org.springframework.security.web.util.matcher.AntPathRequestMatcher
实现,方法支持正则表达式,可以填写多个路径requestMatchers
无论是使用字符串还是接口RequestMatcher
的实现,都支持填写多个值(参数为数组)- Spring Boot 2 不支持使用字符串,仅支持使用
RequestMatcher
的实现 - Spring Boot 3 支持使用 字符串 和
RequestMatcher
的实现
- Spring Boot 2 不支持使用字符串,仅支持使用
使用方法: | 作用 |
---|---|
customizer.mvcMatchers("/a1").permitAll(); | /a1 路径允许所有人访问,基于 MvcRequestMatcher 实现 |
customizer.mvcMatchers(HttpMethod.GET, "/a2").permitAll(); | /a2 仅允许使用 GET 请求 匿名访问 |
customizer.mvcMatchers("/a3").hasAuthority("A1"); | /a3 拥有 A1 权限的用户才能访问 |
customizer.mvcMatchers("/a4").hasAnyAuthority("A1", "A2"); | /a4 拥有 A1 A2 权限 的用户才能访问 |
customizer.mvcMatchers("/a5").hasRole("R1"); | /a5 拥有 R1 角色 的用户才能访问 |
customizer.mvcMatchers("/a6").hasAnyRole("R1", "R2"); | /a6 拥有 R1 R2 角色 的用户才能访问 |
customizer.mvcMatchers("/a7").hasIpAddress("192.168.0.0/16"); | /a7 从 192.168.0.0/16 发送请求可以匿名访问 |
customizer.mvcMatchers("/a8").rememberMe(); | /a8 使用 记住我 功能登陆的用户可以访问 |
customizer.mvcMatchers("/a9").fullyAuthenticated(); | /a9 必须完整验证身份后才能访问,使用 记住我 功能登陆的用户无法访问 |
customizer.mvcMatchers("/a10").denyAll(); | /a10 访问 |
customizer.mvcMatchers("/a11").not().hasAuthority("A1"); | /a11 取反,拥有 A1 权限 才能访问 |
customizer.mvcMatchers("/a12").access("hasAuthority('A1')"); | /a12 与上方 /a3 结果一致 |
customizer.mvcMatchers("/a13").access("hasAuthority('A1') and hasAuthority('A2')"); | /a13 同时 拥有 A1 A2 权限才能访问 |
customizer.mvcMatchers("/a14").access("!hasAuthority('A1')"); | /a14 取反,拥有 A1 权限 才能访问 |
customizer.regexMatchers("/a21").permitAll(); | /a21 与 mvcMatchers 方法雷同,使用 RegexRequestMatcher 实现 |
customizer.antMatchers("/a31").permitAll(); | /a31 与 mvcMatchers 方法雷同,使用 AntPathRequestMatcher 实现 |
使用方法: | 作用 |
---|---|
customizer.requestMatchers("/a1").permitAll(); | /a1 路径允许所有人访问,基于 MvcRequestMatcher 实现 |
customizer.requestMatchers(HttpMethod.GET, "/a2").permitAll(); | /a2 仅允许使用 GET 请求 匿名访问 |
customizer.requestMatchers("/a3").hasAuthority("A1"); | /a3 拥有 A1 权限的用户才能访问 |
customizer.requestMatchers("/a4").hasAnyAuthority("A1", "A2"); | /a4 拥有 A1 A2 权限 的用户才能访问 |
customizer.requestMatchers("/a5").hasRole("R1"); | /a5 拥有 R1 角色 的用户才能访问 |
customizer.requestMatchers("/a6").hasAnyRole("R1", "R2"); | /a6 拥有 R1 R2 角色 的用户才能访问 |
customizer.requestMatchers("/a8").rememberMe(); | /a8 使用 记住我 功能登陆的用户可以访问 |
customizer.requestMatchers("/a9").fullyAuthenticated(); | /a9 必须完整验证身份后才能访问,使用 记住我 功能登陆的用户无法访问 |
customizer.requestMatchers("/a10").denyAll(); | /a10 访问 |
使用方法: | 作用 |
---|---|
customizer.requestMatchers(request -> { /* 这里可以使用 request 进行判断*/ return true;}).permitAll(); | 可以根据 HttpServletRequest 进行自定义判断,最后的 permitAll 也可修改为 hasRole 等等 |