共计 6514 个字符,预计需要花费 17 分钟才能阅读完成。
接入简略,反对多租户,可配置,低代码式的疾速实现一套本人的认证鉴权逻辑
蕴含用户治理、部门治理、角色治理、权限治理,将来还能够反对更多模块,比方数据字典治理、…
预计节俭每个利用相干模块研发工夫 5 人天
对于 oauth2.0 协定来说,有几个概念
- 受权服务器
- 客户端
- 资源服务器
这偏文章次要讲客户端 sdk 实现,资源服务器次要就是对立寄存用户信息的,受权服务器应用 springsecurity 官网的进行小定制。
首先应用 springboot 的主动配置性能,次要配置类有 SecurityConfig,通过编写 META-INF/spring.factories 来实现主动加载配置 bean
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableConfigurationProperties(OauthProperties.class)
public class SecurityConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http,
IntrospectorFilter filter,
CustomLoginUrlAuthenticationEntryPoint entryPoint,
ClientRegistrationRepository clientRegistrationRepository,
CustomRequestCache customRequestCache) throws Exception {ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests();
if(!CollectionUtils.isEmpty(oauthProperties.getIgnoreUris())) {expressionInterceptUrlRegistry.requestMatchers(oauthProperties.getIgnoreUris().stream().map(AntPathRequestMatcher::new).toArray(RequestMatcher[]::new)).permitAll();}
expressionInterceptUrlRegistry.anyRequest().authenticated().and()
.oauth2Login().authorizationEndpoint().authorizationRequestResolver(authorizationRequestResolver(clientRegistrationRepository))
.and()
// .defaultSuccessUrl("/", true);
.successHandler(authenticationSuccessHandler());
http.oauth2Client().and()
.cors().and()
.exceptionHandling().authenticationEntryPoint(entryPoint).and()
.csrf().disable()
.requestCache(requestCacheCustomizer->{requestCacheCustomizer.requestCache(customRequestCache.getRequestCache(http));
});
http.addFilterBefore(filter, AnonymousAuthenticationFilter.class);
return http.build();}
@Bean
public CustomRequestCache customRequestCache() {return new CustomRequestCache();
};
private AuthenticationSuccessHandler authenticationSuccessHandler() {SavedRequestAwareAuthenticationSuccessHandler successHandler = new CustomSavedRequestAwareAuthenticationSuccessHandler();
successHandler.setUseReferer(true);
return successHandler;
}
private OAuth2AuthorizationRequestResolver authorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository) {
DefaultOAuth2AuthorizationRequestResolver authorizationRequestResolver =
new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, "/oauth2/authorization");
authorizationRequestResolver.setAuthorizationRequestCustomizer(authorizationRequestCustomizer());
return authorizationRequestResolver;
}
private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
return customizer -> customizer
.additionalParameters(params -> params.put("tenantId", oauthProperties.getClientId()));
}
@Bean
public CustomLoginUrlAuthenticationEntryPoint customLoginUrlAuthenticationEntryPoint(ObjectMapper objectMapper) {CustomLoginUrlAuthenticationEntryPoint customLoginUrlAuthenticationEntryPoint = new CustomLoginUrlAuthenticationEntryPoint("/oauth2/authorization/auth_server");
customLoginUrlAuthenticationEntryPoint.setObjectMapper(objectMapper);
customLoginUrlAuthenticationEntryPoint.setOauthProperties(oauthProperties);
return customLoginUrlAuthenticationEntryPoint;
};
@Bean
public IntrospectorFilter introspectorFilter(OpaqueTokenIntrospector opaqueTokenIntrospector,
OAuth2AuthorizedClientService oAuth2AuthorizedClientService) {IntrospectorFilter introspectorFilter = new IntrospectorFilter();
introspectorFilter.setOpaqueTokenIntrospector(opaqueTokenIntrospector);
introspectorFilter.setoAuth2AuthorizedClientService(oAuth2AuthorizedClientService);
return introspectorFilter;
}
@Bean
public NimbusOpaqueTokenIntrospector opaqueTokenIntrospector() {String introspectUri = oauthProperties.getIssuerUri() + "/oauth2/introspect";
OAuth2ResourceServerProperties.Opaquetoken opaqueToken = new OAuth2ResourceServerProperties.Opaquetoken();
opaqueToken.setIntrospectionUri(introspectUri);
opaqueToken.setClientId(oauthProperties.getClientId());
opaqueToken.setClientSecret(oauthProperties.getClientSecret());
return new NimbusOpaqueTokenIntrospector(opaqueToken.getIntrospectionUri(), opaqueToken.getClientId(),
opaqueToken.getClientSecret());
}
//@RefreshScope 动静刷新
@Bean
@ConditionalOnMissingBean
public ClientRegistrationRepository clientRegistrationRepository() {return new InMemoryClientRegistrationRepository(this.clientRegistration());
}
@Bean
public OidcUserService oidcUserService(DefaultOAuth2UserService defaultOAuth2UserService) {CustomOidcUserService oidcUserService = new CustomOidcUserService();
oidcUserService.setAccessibleScopes0(scopes);
oidcUserService.setOauth2UserService0(defaultOAuth2UserService);
return oidcUserService;
}
@ConditionalOnMissingBean
@Bean
public ParameterizedTypeReference<Result<OpenAppUser<Map<String, Object>>>> userInfoTypeReference () {return new ParameterizedTypeReference<Result<OpenAppUser<Map<String, Object>>>>() {};}
@Bean
public DefaultOAuth2UserService defaultOAuth2UserService(ParameterizedTypeReference userInfoTypeReference) {CustomDefaultOAuth2UserService defaultOAuth2UserService = new CustomDefaultOAuth2UserService();
defaultOAuth2UserService.setPARAMETERIZED_RESPONSE_TYPE(userInfoTypeReference);
return defaultOAuth2UserService;
}
@Autowired
OauthProperties oauthProperties;
private Set<String> scopes = new HashSet(){
{//add("openid");
add("user");
}
};
private ClientRegistration clientRegistration() {if (oauthProperties.getScopes()!=null) scopes.addAll(oauthProperties.getScopes());
ClientRegistration.Builder auth_server = ClientRegistrations.fromIssuerLocation(oauthProperties.getIssuerUri()).registrationId("auth_server");
return auth_server.clientId(oauthProperties.getClientId())
.clientSecret(oauthProperties.getClientSecret())
.clientName(oauthProperties.getClientName())
//.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
//.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri((StringUtils.hasText(oauthProperties.getServerUrl())?oauthProperties.getServerUrl():"{baseUrl}")+"/login/oauth2/code/{registrationId}")
.scope(scopes)
.userInfoUri(oauthProperties.getIssuerUri()+"/client/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.build();}
}
springsecurity 对于 oauth2.0 的反对还是比较完善的,然而不完全符合咱们对认证受权零碎的要求,所以我这里做了很多自定义,能够说把大部分的拦截器都实现了一些,发现 security 的代码品质也不是很高,很多中央没有做到扩展性,只能重写类。
而后须要接入利用进行配置,所以定义了一个 properties
@ConfigurationProperties(prefix = "oauth")
@Data
public class OauthProperties {
/**
* 客户端 id
*/
private String clientId;
/**
* 客户端密钥
*/
private String clientSecret;
/**
* 客户端名称
*/
private String clientName;
/**
* 接入受权服务器配置 uri
*/
private String issuerUri;
/**
* 权限 默认有 openid,user
*/
private Collection<String> scopes;
/**
* 过滤 url 白名单
*/
private Collection<String> ignoreUris;
/**
* 服务部署地址 (可空,默认读取数据库对应的回调地址)
*/
private String serverUrl;
}
这样接入利用就能够通过配置文件自定义了。
正文完
发表至: spring-security
2021-11-24