matrix.business.oauth2.config.ResourceServerAutoConfiguration Maven / Gradle / Ivy
package matrix.business.oauth2.config;
import lombok.SneakyThrows;
import matrix.boot.based.bean.IgnoreAuthBean;
import matrix.boot.common.dto.Result;
import matrix.boot.common.exception.ServiceException;
import matrix.boot.common.utils.AssertUtil;
import matrix.boot.common.utils.StringUtil;
import matrix.business.oauth2.core.ExcludeRequestMatcher;
import matrix.business.oauth2.properties.OAuth2Properties;
import matrix.business.oauth2.service.OAuthFilterService;
import matrix.business.oauth2.service.impl.DefaultOAuthFilterServiceImpl;
import matrix.business.oauth2.service.impl.DefaultRemoteTokenServiceImpl;
import matrix.business.oauth2.service.impl.DefaultClientDetailServiceImpl;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import matrix.boot.based.utils.WebUtil;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import java.util.*;
import java.util.stream.Collectors;
/**
* 资源服务器配置
*
* @author wangcheng
* 2021/8/27
**/
@ConditionalOnProperty(value = {"matrix.business.oauth2.enabled", "matrix.business.oauth2.resource-server.enabled"})
@Configuration
@EnableConfigurationProperties({OAuth2Properties.class, OAuth2Properties.AuthorizationServerProperties.class, OAuth2Properties.ResourceServerProperties.class})
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerAutoConfiguration extends ResourceServerConfigurerAdapter {
/**
* 默认不用资源认证的链接
*/
private static final List NOT_RESOURCE_VALIDATE_URLS = Arrays.asList("/oauth/**", "/login", "/error");
/**
* oauth2配置
*/
private final OAuth2Properties oAuth2Properties;
@Autowired(required = false)
private RestTemplate restTemplate;
@Autowired
private OAuth2WebSecurityExpressionHandler expressionHandler;
/**
* 忽略验证的beans
*/
@Autowired
private ObjectProvider ignoreAuthBeans;
public ResourceServerAutoConfiguration(OAuth2Properties oAuth2Properties) {
this.oAuth2Properties = oAuth2Properties;
}
/**
* 当前资源服务器的一些配置, 如资源服务器ID
*
* @param resources 资源信息
*/
@SneakyThrows
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
//认证服务配置
OAuth2Properties.AuthorizationServerProperties authorizationServerProperties = oAuth2Properties.getAuthorizationServer();
//资源服务配置
OAuth2Properties.ResourceServerProperties resourceServerProperties = oAuth2Properties.getResourceServer();
//参数校验
AssertUtil.notNullTip(resourceServerProperties.getResourceId(), "matrix.business.oauth2.resource-server.resource-id");
//资源服务Token校验服务
ResourceServerTokenServices resourceServerTokenServices;
if (authorizationServerProperties != null && authorizationServerProperties.isEnabled()) {
//认证服务器也打开,代表本服务即是认证服务器也是资源服务器
resourceServerTokenServices = new DefaultTokenServices();
((DefaultTokenServices) resourceServerTokenServices).setTokenStore(WebUtil.getBean(TokenStore.class));
((DefaultTokenServices) resourceServerTokenServices).setAuthenticationManager(WebUtil.getBean(AuthenticationManager.class));
if (authorizationServerProperties.getClientDetailsClass() != null) {
try {
((DefaultTokenServices) resourceServerTokenServices).setClientDetailsService(authorizationServerProperties.getClientDetailsClass().newInstance());
} catch (Exception e) {
throw new ServiceException(e);
}
} else {
//使用默认的客户端
((DefaultTokenServices) resourceServerTokenServices).setClientDetailsService(new DefaultClientDetailServiceImpl());
}
((DefaultTokenServices) resourceServerTokenServices).setAccessTokenValiditySeconds(oAuth2Properties.getAuthorizationServer().getDefaultAccessTokenValiditySeconds());
((DefaultTokenServices) resourceServerTokenServices).setRefreshTokenValiditySeconds(oAuth2Properties.getAuthorizationServer().getDefaultRefreshTokenValiditySeconds());
((DefaultTokenServices) resourceServerTokenServices).setSupportRefreshToken(true);
} else {
//参数校验
AssertUtil.notNullTip(resourceServerProperties.getAuthServerUrl(), "matrix.business.oauth2.resource-server.auth-server-url");
AssertUtil.notNullTip(resourceServerProperties.getClientId(), "matrix.business.oauth2.resource-server.client-id");
AssertUtil.notNullTip(resourceServerProperties.getClientSecret(), "matrix.business.oauth2.resource-server.client-secret");
//本服务只是单纯的资源服务
resourceServerTokenServices = new DefaultRemoteTokenServiceImpl(Boolean.TRUE.equals(resourceServerProperties.getInternalAuthServer()) ? restTemplate : null);
//请求认证服务器验证URL
((DefaultRemoteTokenServiceImpl) resourceServerTokenServices).setAuthServerUrl(resourceServerProperties.getAuthServerUrl());
//设置是否jwt模式
((DefaultRemoteTokenServiceImpl) resourceServerTokenServices).setJwtLocalParse(resourceServerProperties.isJwtLocalParse());
//在认证服务器配置的客户端id
((DefaultRemoteTokenServiceImpl) resourceServerTokenServices).setClientId(resourceServerProperties.getClientId());
//在认证服务器配置的客户端密码
((DefaultRemoteTokenServiceImpl) resourceServerTokenServices).setClientSecret(resourceServerProperties.getClientSecret());
//设置TOKEN转换器
if (resourceServerProperties.getJwtAccessTokenConverterClass() != null) {
((DefaultRemoteTokenServiceImpl) resourceServerTokenServices).setAccessTokenConverter(resourceServerProperties.getJwtAccessTokenConverterClass().newInstance());
}
}
//配置当前资源服务器的ID
resources.resourceId(oAuth2Properties.getResourceServer().getResourceId()).tokenServices(resourceServerTokenServices);
//表达式解析器
resources.expressionHandler(expressionHandler);
//设置auth进入点
resources.authenticationEntryPoint(new DefaultOAuth2AuthenticationEntryPoint());
}
@Override
public void configure(HttpSecurity http) throws Exception {
//资源服务配置
OAuth2Properties.ResourceServerProperties resourceServerProperties = oAuth2Properties.getResourceServer();
if (resourceServerProperties.getHttpSecurityClass() != null) {
resourceServerProperties.getHttpSecurityClass().newInstance().init(http);
} else {
//忽略的uri
Set ignoreAuthUris = new HashSet<>();
//获取黑白名单过滤服务类
OAuthFilterService oAuthFilterService;
if (oAuth2Properties.getAuthorizationServer() != null) {
if (!CollectionUtils.isEmpty(oAuth2Properties.getAuthorizationServer().getIgnoreAuthUris())) {
ignoreAuthUris.addAll(oAuth2Properties.getAuthorizationServer().getIgnoreAuthUris());
}
oAuthFilterService = oAuth2Properties.getAuthorizationServer().getOauthFilterClass() == null
? new DefaultOAuthFilterServiceImpl()
: oAuth2Properties.getAuthorizationServer().getOauthFilterClass().newInstance();
} else {
oAuthFilterService = oAuth2Properties.getResourceServer().getOauthFilterClass() == null
? new DefaultOAuthFilterServiceImpl()
: oAuth2Properties.getResourceServer().getOauthFilterClass().newInstance();
}
if (!CollectionUtils.isEmpty(oAuth2Properties.getResourceServer().getIgnoreAuthUris())) {
ignoreAuthUris.addAll(oAuth2Properties.getResourceServer().getIgnoreAuthUris());
}
//默认忽略头验证的urls
if (!CollectionUtils.isEmpty(NOT_RESOURCE_VALIDATE_URLS)) {
ignoreAuthUris.addAll(NOT_RESOURCE_VALIDATE_URLS);
}
//忽略的验证链接
List ignoreAuthBeanList = ignoreAuthBeans.orderedStream().collect(Collectors.toList());
if (!CollectionUtils.isEmpty(ignoreAuthBeanList)) {
ignoreAuthUris.addAll(ignoreAuthBeanList.stream().flatMap(item -> item.getIgnoreResourceUris().stream()).collect(Collectors.toList()));
}
//排除链接配置
ExcludeRequestMatcher excludeRequestMatcher = new ExcludeRequestMatcher(ignoreAuthUris, null, oAuthFilterService);
if (CollectionUtils.isEmpty(resourceServerProperties.getSecurityConfig())) {
//默认配置
http.requestMatcher(new OrRequestMatcher(excludeRequestMatcher)).authorizeRequests().anyRequest().authenticated();
} else {
//用户配置解析
List securityConfigs = resourceServerProperties.getSecurityConfig();
List requestMatchers = new ArrayList<>();
requestMatchers.add(excludeRequestMatcher);
securityConfigs.forEach(securityConfig -> {
Assert.state(!StringUtil.isEmpty(securityConfig.getUris()), "oauth2 security config uris not be null");
for (String uri : securityConfig.getUris().split(",")) {
requestMatchers.add(new AntPathRequestMatcher(uri));
}
});
ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry = http.requestMatcher(new OrRequestMatcher(requestMatchers)).authorizeRequests();
for (OAuth2Properties.SecurityConfig securityConfig : securityConfigs) {
String[] uris = securityConfig.getUris().split(",");
if (!StringUtil.isEmpty(securityConfig.getClientScopes())) {
//判断范围
registry = registry.antMatchers(uris).access("#oauth2.hasAnyScope(" + securityConfig.getClientScopes() + ")");
} else if (!StringUtil.isEmpty(securityConfig.getClientRoles())) {
//判断角色
registry = registry.antMatchers(uris).access("#oauth2.clientHasAnyRole(" + securityConfig.getClientRoles() + ")");
} else {
registry = registry.antMatchers(uris).authenticated();
}
}
registry.and().csrf().disable().cors().disable();
}
}
}
/**
* 表达式解析器
*
* @param applicationContext 上下文
* @return 表达式解析器
*/
@Bean
public OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler(ApplicationContext applicationContext) {
OAuth2WebSecurityExpressionHandler expressionHandler = new OAuth2WebSecurityExpressionHandler();
expressionHandler.setApplicationContext(applicationContext);
return expressionHandler;
}
/**
* 默认验证进入点
*/
public static class DefaultOAuth2AuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint {
@Override
protected ResponseEntity> enhanceResponse(ResponseEntity> response, Exception exception) {
ResponseEntity> responseEntity = super.enhanceResponse(response, exception);
return new ResponseEntity