关键词占位:
spring security 整合 企业微信 oauth2 OAuth2
SpringSecurity6 整合 企业微信OAuth2
spring 整合 OAuth2
spring 整合 企业微信 OAuth2
https://developer.work.weixin.qq.com/document/path/90597
接口并不通用,但是跟OAuth2流程一致
├──src
│ └──main
│ ├──java
│ │ └──com
│ │ └──qwei
│ │ └──auth
│ │ ├──AuthApplication.java
│ │ ├──bean #Bean转换格式
│ │ │ ├──AccessToken.java
│ │ │ ├──QwOauth2UserInfo.java
│ │ │ └──UserInfo.java
│ │ ├──config #配置类,手动注册Bean
│ │ │ ├──QWeiAuthConfiguration.java
│ │ │ ├──QWeiOauth2ConfigProperties.java
│ │ │ ├──QWeiRedirectStrategy.java
│ │ │ ├──RedisConfig.java
│ │ │ └──RedisOAuth2AuthorizationRequestRepository.java
│ │ ├──constant #企业微信常量
│ │ │ └──WeConstants.java
│ │ ├──converter #不同时期不同的converter重写
│ │ │ ├──QWeiMapOAuth2AccessTokenResponseConverter.java
│ │ │ ├──QWeiOAuth2AuthorizationGrantRequestEntityConverter.java
│ │ │ └──QWeiOAuth2UserRequestEntityConverter.java
│ │ ├──endpoint #检测到请求资源,拦截到此,重定向至认证服务器之前,定义request实体
│ │ │ └──QwOAuth2AuthorizationRequestResolver.java
│ │ ├──handler #登录成功失败
│ │ │ ├──JwtAuthenticationFailureHandler.java
│ │ │ ├──JwtAuthenticationSuccessHandler.java
│ │ │ ├──Oauth2AuthenticationSuccessHandler.java
│ │ │ └──QWeiLogoutSuccessHandler.java
│ │ ├──provider
│ │ │ └──QWeiAuthenticationProvider.java
│ │ ├──rest
│ │ │ ├──RestResult.java
│ │ │ └──RestResultUtils.java
│ │ ├──service
│ │ │ └──QWeiUserDetailsService.java
│ │ ├──token #Token生成器
│ │ │ └──TokenManager.java
│ │ └──util
│ │ ├──RedisCacheUtil.java
│ │ └──SuiteAccessTokenHttpUtil.java
-
HttpSecurity implements SecurityBuilder
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity> implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity>
public interface SecurityBuilder<O> { O build() throws Exception; }
- AbstractConfiguredSecurityBuilder extends AbstractSecurityBuilder
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> { @Override public final O build() throws Exception { if (this.building.compareAndSet(false, true)) { // doBuild()方法由子类实现 this.object = doBuild(); return this.object; } throw new AlreadyBuiltException("This object has already been built"); } }
//org.springframework.security.config.annotation.web.builders.HttpSecurity#performBuild
@Override
private DefaultSecurityFilterChain performBuild() {
ExpressionUrlAuthorizationConfigurer<?> expressionConfigurer = getConfigurer(
ExpressionUrlAuthorizationConfigurer.class);
AuthorizeHttpRequestsConfigurer<?> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class);
boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent,
"authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one.");
this.filters.sort(OrderComparator.INSTANCE);
List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
for (Filter filter : this.filters) {
sortedFilters.add(((OrderedFilter) filter).filter);
}
return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
}为什么可以手动注册Defaultxxx处理类,重载class需要处理加载路径的问题,也多了很多无意义源代码
只要实现以下两点 ---> 对于任意的OAuth2实现都可以通
- 手动注册DefaultXXX
- 重写converter
public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> {
}
//org.springframework.security.config.annotation.web.configurers.oauth2.client.//OAuth2LoginConfigurer#init
// 并且这些init方法去获取bean的时候,首先去类库加载是否已经存在这些类,否则直接new DefaultXXX,知道了这一点还可以看到很多DefaultXXX 内部有很多转换器,我们可以重写转换器相当于自定义DefaultXXX的效果
// ====================== 重写converter //org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient#setRequestEntityConverter
//org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient#setRestOperations....
//============================ 手动注册bean
// ResolvableType resolvableType = //ResolvableType.forClassWithGenerics(OAuth2AccessTokenResponseClient.class,
// OAuth2AuthorizationCodeGrantRequest.class);
// OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> bean = //getBeanOrNull(resolvableType);
// return (bean != null) ? bean : new DefaultAuthorizationCodeTokenResponseClient(); 前置条件: 满足企业微信开发应用条件
server:
port: 8000
spring:
application:
name: @artifactId@
data:
redis:
port: 6378
host: localhost
password: qwchat9527
qw:
oauth2:
#以自己的应用和企业信息为准,替换下内容
registration:
qwchat-client:
provider: qw
clientName: qwchat-client
clientId: AAA
client-secret: AAA
authorizationGrantType: authorization_code
redirectUri: http://可信域名/login/oauth2/code/qwchat-client
scope:
- snsapi_privateinfo
# - snsapi_base
# qwchat-client2 ....
provider:
qwchat-client: #需要与registration一致
authorization-uri: https://open.weixin.qq.com/connect/oauth2/authorize
token-uri: https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserinfo3rd
user-info-uri: https://qyapi.weixin.qq.com/cgi-bin/service/auth/getuserdetail3rd
user-name-attribute: open_userid
#open_userid \ openid
success-urls:
qwchat-client: http://www.baidu.com/
token:
auth:
token:
expire:
seconds: 18000
secret-key: SecretKey012345678901234567890123456789012345678901234567890123456789