spring cloud oauth2 使用说明


spring cloud oauth2 使用说明

************************

导入 jar 包

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

 说明:spring-cloud-starter-oauth2中已经包含了security,不需要再导入security

            

 

************************

自动配置类

OAuth2AutoConfiguration:oauth2自动配置类

@Configuration
@ConditionalOnClass({OAuth2AccessToken.class, WebMvcConfigurer.class})
@Import({OAuth2AuthorizationServerConfiguration.class, OAuth2MethodSecurityConfiguration.class, OAuth2ResourceServerConfiguration.class, OAuth2RestOperationsConfiguration.class})
@AutoConfigureBefore({WebMvcAutoConfiguration.class})
@EnableConfigurationProperties({OAuth2ClientProperties.class})
public class OAuth2AutoConfiguration {
    private final OAuth2ClientProperties credentials;

    public OAuth2AutoConfiguration(OAuth2ClientProperties credentials) {
        this.credentials = credentials;
    }

    @Bean
    public ResourceServerProperties resourceServerProperties() {
        return new ResourceServerProperties(this.credentials.getClientId(), this.credentials.getClientSecret());
    }
}

说明:该自动配置类导入OAuth2AuthorizationServerConfiguration、OAuth2MethodSecurityConfiguration、OAuth2ResourceServerConfiguration、OAuth2RestOperationsConfiguration,

读取属性文件配置OAuth2ClientProperties

OAuth2ClientProperties

@ConfigurationProperties(
    prefix = "security.oauth2.client"
)
public class OAuth2ClientProperties {
    private String clientId;
    private String clientSecret = UUID.randomUUID().toString();
    private boolean defaultSecret = true;

    public OAuth2ClientProperties() {

OAuth2AuthorizationServerConfiguration:oauth2认证服务器配置

@Configuration
@ConditionalOnClass({EnableAuthorizationServer.class})
@ConditionalOnMissingBean({AuthorizationServerConfigurer.class})
                     //当容器中不存在authorizationServerConfigurer实例时创建OAuth2AuthorizationServerConfiguration,
                      一般情况下,资源服务器会创建authorizationServerConfigurer的实例

@ConditionalOnBean({AuthorizationServerEndpointsConfiguration.class})
@EnableConfigurationProperties({AuthorizationServerProperties.class})
@Import({AuthorizationServerTokenServicesConfiguration.class})
public class OAuth2AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    private static final Log logger = LogFactory.getLog(OAuth2AuthorizationServerConfiguration.class);
    private final BaseClientDetails details;
    private final AuthenticationManager authenticationManager;
    private final TokenStore tokenStore;
    private final AccessTokenConverter tokenConverter;
    private final AuthorizationServerProperties properties;

****************
内部类

    @Configuration
    @ConditionalOnMissingBean({BaseClientDetails.class})
    protected static class BaseClientDetailsConfiguration {
        private final OAuth2ClientProperties client;

        protected BaseClientDetailsConfiguration(OAuth2ClientProperties client) {
            this.client = client;
        }

        @Bean
        @ConfigurationProperties(
            prefix = "security.oauth2.client"
        )
        public BaseClientDetails oauth2ClientDetails() {
            BaseClientDetails details = new BaseClientDetails();
            if (this.client.getClientId() == null) {
                this.client.setClientId(UUID.randomUUID().toString());
            }

            details.setClientId(this.client.getClientId());
            details.setClientSecret(this.client.getClientSecret());
            details.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "password", "client_credentials", "implicit", "refresh_token"));
            details.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
            details.setRegisteredRedirectUri(Collections.emptySet());
            return details;
        }
    }

BaseClientDetails:客户端配置属性

public class BaseClientDetails implements ClientDetails {

    @JsonProperty("client_id")
    @com.fasterxml.jackson.annotation.JsonProperty("client_id")
    private String clientId;

    @JsonProperty("client_secret")
    @com.fasterxml.jackson.annotation.JsonProperty("client_secret")
    private String clientSecret;

    @JsonDeserialize(using = JacksonArrayOrStringDeserializer.class)
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class)
    private Set<String> scope;

    @JsonProperty("resource_ids")
    @JsonDeserialize(using = JacksonArrayOrStringDeserializer.class)
    @com.fasterxml.jackson.annotation.JsonProperty("resource_ids")
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class)
    private Set<String> resourceIds;

    @JsonProperty("authorized_grant_types")
    @JsonDeserialize(using = JacksonArrayOrStringDeserializer.class)
    @com.fasterxml.jackson.annotation.JsonProperty("authorized_grant_types")
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class)
    private Set<String> authorizedGrantTypes;
   
    @JsonProperty("redirect_uri")
    @JsonDeserialize(using = JacksonArrayOrStringDeserializer.class)
    @com.fasterxml.jackson.annotation.JsonProperty("redirect_uri")
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class)
    private Set<String> registeredRedirectUris;

    @JsonProperty("autoapprove")
    @JsonDeserialize(using = JacksonArrayOrStringDeserializer.class)
    @com.fasterxml.jackson.annotation.JsonProperty("autoapprove")
    @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Jackson2ArrayOrStringDeserializer.class)
    private Set<String> autoApproveScopes;

    private List<GrantedAuthority> authorities;

    @JsonProperty("access_token_validity")
    @com.fasterxml.jackson.annotation.JsonProperty("access_token_validity")
    private Integer accessTokenValiditySeconds;

    @JsonProperty("refresh_token_validity")
    @com.fasterxml.jackson.annotation.JsonProperty("refresh_token_validity")
    private Integer refreshTokenValiditySeconds;

    @JsonIgnore
    @com.fasterxml.jackson.annotation.JsonIgnore
    private Map<String, Object> additionalInformation;

AuthorizationServerProperties:认证服务器自动配置属性

@ConfigurationProperties(
    prefix = "security.oauth2.authorization"
)
public class AuthorizationServerProperties {
    private String checkTokenAccess;
    private String tokenKeyAccess;
    private String realm;
    private AuthorizationServerProperties.Jwt jwt = new AuthorizationServerProperties.Jwt();

    public AuthorizationServerProperties() {

***************
内部类

    public class Jwt {
        private String keyValue;
        private String keyStore;
        private String keyStorePassword;
        private String keyAlias;
        private String keyPassword;

        public Jwt() {

ResourceServerProperties:资源服务器自动配置属性

@ConfigurationProperties(
    prefix = "security.oauth2.resource"
)
public class ResourceServerProperties implements BeanFactoryAware, InitializingBean {
    @JsonIgnore
    private final String clientId;
    @JsonIgnore
    private final String clientSecret;
    @JsonIgnore
    private ListableBeanFactory beanFactory;
    private String serviceId;
    private String id;
    private String userInfoUri;
    private String tokenInfoUri;
    private boolean preferTokenInfo;
    private String tokenType;
    private ResourceServerProperties.Jwt jwt;
    private ResourceServerProperties.Jwk jwk;

    public ResourceServerProperties() {
        this((String)null, (String)null);
    }

    public ResourceServerProperties(String clientId, String clientSecret) {

***************
内部类

    public class Jwk {
        private String keySetUri;

        public Jwk() {

***************
内部类

    public class Jwt {
        private String keyValue;
        private String keyUri;
        private String keyStore;
        private String keyStorePassword;
        private String keyAlias;
        private String keyPassword;

        public Jwt() {

 

************************

认证服务器配置

*********************

相关注解

@EnableAuthorizationServer:启动认证服务器

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AuthorizationServerEndpointsConfiguration.class, AuthorizationServerSecurityConfiguration.class})
public @interface EnableAuthorizationServer {
}

说明:注解导入AuthorizationServerEndpointsConfiguration、AuthorizationServerSecurityConfiguration

*********************

注解导入类

AuthorizationServerEndpointsConfiguration:认证服务器endPoints配置

@Configuration
@Import({AuthorizationServerEndpointsConfiguration.TokenKeyEndpointRegistrar.class})
public class AuthorizationServerEndpointsConfiguration {
    private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer();
    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();

    public AuthorizationServerEndpointsConfiguration() {
    }

    @PostConstruct
    public void init() {
        Iterator var1 = this.configurers.iterator();

        while(var1.hasNext()) {
            AuthorizationServerConfigurer configurer = (AuthorizationServerConfigurer)var1.next();

            try {
                configurer.configure(this.endpoints);
            } catch (Exception var4) {
                throw new IllegalStateException("Cannot configure enpdoints", var4);
            }
        }

        this.endpoints.setClientDetailsService(this.clientDetailsService);
    }

    @Bean
    public AuthorizationEndpoint authorizationEndpoint() throws Exception {
        AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint();
        FrameworkEndpointHandlerMapping mapping = this.getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
        authorizationEndpoint.setUserApprovalPage(this.extractPath(mapping, "/oauth/confirm_access"));
        authorizationEndpoint.setProviderExceptionHandler(this.exceptionTranslator());
        authorizationEndpoint.setErrorPage(this.extractPath(mapping, "/oauth/error"));
        authorizationEndpoint.setTokenGranter(this.tokenGranter());
        authorizationEndpoint.setClientDetailsService(this.clientDetailsService);
        authorizationEndpoint.setAuthorizationCodeServices(this.authorizationCodeServices());
        authorizationEndpoint.setOAuth2RequestFactory(this.oauth2RequestFactory());
        authorizationEndpoint.setOAuth2RequestValidator(this.oauth2RequestValidator());
        authorizationEndpoint.setUserApprovalHandler(this.userApprovalHandler());
        authorizationEndpoint.setRedirectResolver(this.redirectResolver());
        return authorizationEndpoint;
    }

    @Bean
    public TokenEndpoint tokenEndpoint() throws Exception {
        TokenEndpoint tokenEndpoint = new TokenEndpoint();
        tokenEndpoint.setClientDetailsService(this.clientDetailsService);
        tokenEndpoint.setProviderExceptionHandler(this.exceptionTranslator());
        tokenEndpoint.setTokenGranter(this.tokenGranter());
        tokenEndpoint.setOAuth2RequestFactory(this.oauth2RequestFactory());
        tokenEndpoint.setOAuth2RequestValidator(this.oauth2RequestValidator());
        tokenEndpoint.setAllowedRequestMethods(this.allowedTokenEndpointRequestMethods());
        return tokenEndpoint;
    }

    @Bean
    public CheckTokenEndpoint checkTokenEndpoint() {
        CheckTokenEndpoint endpoint = new CheckTokenEndpoint(this.getEndpointsConfigurer().getResourceServerTokenServices());
        endpoint.setAccessTokenConverter(this.getEndpointsConfigurer().getAccessTokenConverter());
        endpoint.setExceptionTranslator(this.exceptionTranslator());
        return endpoint;
    }

    @Bean
    public WhitelabelApprovalEndpoint whitelabelApprovalEndpoint() {
        return new WhitelabelApprovalEndpoint();
    }

    @Bean
    public WhitelabelErrorEndpoint whitelabelErrorEndpoint() {
        return new WhitelabelErrorEndpoint();
    }

    @Bean
    public FrameworkEndpointHandlerMapping oauth2EndpointHandlerMapping() throws Exception {
        return this.getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
    }

    @Bean
    public FactoryBean<ConsumerTokenServices> consumerTokenServices() throws Exception {
        return new AbstractFactoryBean<ConsumerTokenServices>() {
            public Class<?> getObjectType() {
                return ConsumerTokenServices.class;
            }

            protected ConsumerTokenServices createInstance() throws Exception {
                return AuthorizationServerEndpointsConfiguration.this.getEndpointsConfigurer().getConsumerTokenServices();
            }
        };
    }

    @Bean
    public FactoryBean<AuthorizationServerTokenServices> defaultAuthorizationServerTokenServices() {
        return new AuthorizationServerEndpointsConfiguration.AuthorizationServerTokenServicesFactoryBean(this.endpoints);
    }

    @Component
    protected static class TokenKeyEndpointRegistrar implements BeanDefinitionRegistryPostProcessor {
        private BeanDefinitionRegistry registry;

        protected TokenKeyEndpointRegistrar() {
        }

        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, JwtAccessTokenConverter.class, false, false);
            if (names.length > 0) {
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TokenKeyEndpoint.class);
                builder.addConstructorArgReference(names[0]);
                this.registry.registerBeanDefinition(TokenKeyEndpoint.class.getName(), builder.getBeanDefinition());
            }

        }//注册tokenKeyPoint类

        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            this.registry = registry;
        }
    }

    protected static class AuthorizationServerTokenServicesFactoryBean extends AbstractFactoryBean<AuthorizationServerTokenServices> {
        private AuthorizationServerEndpointsConfigurer endpoints;

        protected AuthorizationServerTokenServicesFactoryBean() {
        }

        public AuthorizationServerTokenServicesFactoryBean(AuthorizationServerEndpointsConfigurer endpoints) {
            this.endpoints = endpoints;
        }

        public Class<?> getObjectType() {
            return AuthorizationServerTokenServices.class;
        }

        protected AuthorizationServerTokenServices createInstance() throws Exception {
            return this.endpoints.getDefaultAuthorizationServerTokenServices();
        }
    }
}

AuthorizationServerEndpointsConfigurer:认证服务器endpoints配置参数

public final class AuthorizationServerEndpointsConfigurer {
    private AuthorizationServerTokenServices tokenServices;
    private ConsumerTokenServices consumerTokenServices;
    private AuthorizationCodeServices authorizationCodeServices;
    private ResourceServerTokenServices resourceTokenServices;
    private TokenStore tokenStore;                       //设置token存储方式
    private TokenEnhancer tokenEnhancer;                 //jwt添加自定义字段
    private AccessTokenConverter accessTokenConverter;   //jwt数据转换设置key
    private ApprovalStore approvalStore;
    private TokenGranter tokenGranter;
    private OAuth2RequestFactory requestFactory;
    private OAuth2RequestValidator requestValidator;
    private UserApprovalHandler userApprovalHandler;
    private AuthenticationManager authenticationManager; //password认证时使用
    private ClientDetailsService clientDetailsService;
    private String prefix;
    private Map<String, String> patternMap = new HashMap();
    private Set<HttpMethod> allowedTokenEndpointRequestMethods = new HashSet();
    private FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping;
    private boolean approvalStoreDisabled;
    private List<Object> interceptors = new ArrayList();
    private DefaultTokenServices defaultTokenServices;
    private UserDetailsService userDetailsService;       //认证服务器用户认证
    private boolean tokenServicesOverride = false;
    private boolean userDetailsServiceOverride = false;
    private boolean reuseRefreshToken = true;
    private WebResponseExceptionTranslator<OAuth2Exception> exceptionTranslator;
    private RedirectResolver redirectResolver;

*****************
常用方法

    public AuthorizationServerEndpointsConfigurer authenticationManager(AuthenticationManager authenticationManager) {
    public AuthorizationServerEndpointsConfigurer userDetailsService(UserDetailsService userDetailsService) {

    public AuthorizationServerEndpointsConfigurer tokenStore(TokenStore tokenStore) {
    public AuthorizationServerEndpointsConfigurer tokenEnhancer(TokenEnhancer tokenEnhancer) {
    public AuthorizationServerEndpointsConfigurer accessTokenConverter(AccessTokenConverter accessTokenConverter) {

支持的token存储方式

JwkTokenStore

public class JwtTokenStore implements TokenStore {
    private JwtAccessTokenConverter jwtTokenEnhancer;
    private ApprovalStore approvalStore;


********************
JwtTokenStore

public class JwtTokenStore implements TokenStore {
    private JwtAccessTokenConverter jwtTokenEnhancer;
    private ApprovalStore approvalStore;

    public JwtTokenStore(JwtAccessTokenConverter jwtTokenEnhancer) {


********************
RedisTokenStore

public class RedisTokenStore implements TokenStore {
    private static final String ACCESS = "access:";
    private static final String AUTH_TO_ACCESS = "auth_to_access:";
    private static final String AUTH = "auth:";
    private static final String REFRESH_AUTH = "refresh_auth:";
    private static final String ACCESS_TO_REFRESH = "access_to_refresh:";
    private static final String REFRESH = "refresh:";
    private static final String REFRESH_TO_ACCESS = "refresh_to_access:";
    private static final String CLIENT_ID_TO_ACCESS = "client_id_to_access:";
    private static final String UNAME_TO_ACCESS = "uname_to_access:";
    private static final boolean springDataRedis_2_0 = ClassUtils.isPresent("org.springframework.data.redis.connection.RedisStandaloneConfiguration", RedisTokenStore.class.getClassLoader());
    private final RedisConnectionFactory connectionFactory;
    private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
    private RedisTokenStoreSerializationStrategy serializationStrategy = new JdkSerializationStrategy();
    private String prefix = "";
    private Method redisConnectionSet_2_0;

    public RedisTokenStore(RedisConnectionFactory connectionFactory) {



********************
InMemoryTokenStore

public class InMemoryTokenStore implements TokenStore {
    private static final int DEFAULT_FLUSH_INTERVAL = 1000;
    private final ConcurrentHashMap<String, OAuth2AccessToken> accessTokenStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, OAuth2AccessToken> authenticationToAccessTokenStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, Collection<OAuth2AccessToken>> userNameToAccessTokenStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, Collection<OAuth2AccessToken>> clientIdToAccessTokenStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, OAuth2RefreshToken> refreshTokenStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, String> accessTokenToRefreshTokenStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, OAuth2Authentication> authenticationStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, OAuth2Authentication> refreshTokenAuthenticationStore = new ConcurrentHashMap();
    private final ConcurrentHashMap<String, String> refreshTokenToAccessTokenStore = new ConcurrentHashMap();
    private final DelayQueue<InMemoryTokenStore.TokenExpiry> expiryQueue = new DelayQueue();
    private final ConcurrentHashMap<String, InMemoryTokenStore.TokenExpiry> expiryMap = new ConcurrentHashMap();
    private int flushInterval = 1000;
    private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
    private AtomicInteger flushCounter = new AtomicInteger(0);

    public InMemoryTokenStore() {



********************
JdbcTokenStore

public class JdbcTokenStore implements TokenStore {
    private static final Log LOG = LogFactory.getLog(JdbcTokenStore.class);
    private static final String DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)";
    private static final String DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_access_token where token_id = ?";
    private static final String DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_access_token where token_id = ?";
    private static final String DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT = "select token_id, token from oauth_access_token where authentication_id = ?";
    private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ? and client_id = ?";
    private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ?";
    private static final String DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT = "select token_id, token from oauth_access_token where client_id = ?";
    private static final String DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT = "delete from oauth_access_token where token_id = ?";
    private static final String DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT = "delete from oauth_access_token where refresh_token = ?";
    private static final String DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT = "insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)";
    private static final String DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_refresh_token where token_id = ?";
    private static final String DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_refresh_token where token_id = ?";
    private static final String DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT = "delete from oauth_refresh_token where token_id = ?";
    private String insertAccessTokenSql = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)";
    private String selectAccessTokenSql = "select token_id, token from oauth_access_token where token_id = ?";
    private String selectAccessTokenAuthenticationSql = "select token_id, authentication from oauth_access_token where token_id = ?";
    private String selectAccessTokenFromAuthenticationSql = "select token_id, token from oauth_access_token where authentication_id = ?";
    private String selectAccessTokensFromUserNameAndClientIdSql = "select token_id, token from oauth_access_token where user_name = ? and client_id = ?";
    private String selectAccessTokensFromUserNameSql = "select token_id, token from oauth_access_token where user_name = ?";
    private String selectAccessTokensFromClientIdSql = "select token_id, token from oauth_access_token where client_id = ?";
    private String deleteAccessTokenSql = "delete from oauth_access_token where token_id = ?";
    private String insertRefreshTokenSql = "insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)";
    private String selectRefreshTokenSql = "select token_id, token from oauth_refresh_token where token_id = ?";
    private String selectRefreshTokenAuthenticationSql = "select token_id, authentication from oauth_refresh_token where token_id = ?";
    private String deleteRefreshTokenSql = "delete from oauth_refresh_token where token_id = ?";
    private String deleteAccessTokenFromRefreshTokenSql = "delete from oauth_access_token where refresh_token = ?";
    private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
    private final JdbcTemplate jdbcTemplate;

    public JdbcTokenStore(DataSource dataSource) {

AuthorizationServerSecurityConfiguration:认证服务器安全配置

@Configuration
@Order(0)
@Import({ClientDetailsServiceConfiguration.class, AuthorizationServerEndpointsConfiguration.class})
       //该配置类导入ClientDetailsServiceConfiguration、AuthorizationServerEndpointsConfiguration

public class AuthorizationServerSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();
    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private AuthorizationServerEndpointsConfiguration endpoints;

    public AuthorizationServerSecurityConfiguration() {
    }

    @Autowired
    public void configure(ClientDetailsServiceConfigurer clientDetails) throws Exception {
        Iterator var2 = this.configurers.iterator();

        while(var2.hasNext()) {
            AuthorizationServerConfigurer configurer = (AuthorizationServerConfigurer)var2.next();
            configurer.configure(clientDetails);
        }

    }

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    }

    protected void configure(HttpSecurity http) throws Exception {
        AuthorizationServerSecurityConfigurer configurer = new AuthorizationServerSecurityConfigurer();
        FrameworkEndpointHandlerMapping handlerMapping = this.endpoints.oauth2EndpointHandlerMapping();
        http.setSharedObject(FrameworkEndpointHandlerMapping.class, handlerMapping);
        this.configure(configurer);
        http.apply(configurer);
        String tokenEndpointPath = handlerMapping.getServletPath("/oauth/token");
        String tokenKeyPath = handlerMapping.getServletPath("/oauth/token_key");
        String checkTokenPath = handlerMapping.getServletPath("/oauth/check_token");
        if (!this.endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride()) {
            UserDetailsService userDetailsService = (UserDetailsService)http.getSharedObject(UserDetailsService.class);
            this.endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
        }

        ((RequestMatcherConfigurer)((HttpSecurity)((AuthorizedUrl)((AuthorizedUrl)((AuthorizedUrl)http.authorizeRequests().antMatchers(new String[]{tokenEndpointPath})).fullyAuthenticated().antMatchers(new String[]{tokenKeyPath})).access(configurer.getTokenKeyAccess()).antMatchers(new String[]{checkTokenPath})).access(configurer.getCheckTokenAccess()).and()).requestMatchers().antMatchers(new String[]{tokenEndpointPath, tokenKeyPath, checkTokenPath})).and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
        http.setSharedObject(ClientDetailsService.class, this.clientDetailsService);
    }

    protected void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        Iterator var2 = this.configurers.iterator();

        while(var2.hasNext()) {
            AuthorizationServerConfigurer configurer = (AuthorizationServerConfigurer)var2.next();
            configurer.configure(oauthServer);
        }

    }
}

ClientDetailsServiceConfiguration:认证客户端配置

@Configuration
public class ClientDetailsServiceConfiguration {
    private ClientDetailsServiceConfigurer configurer = new ClientDetailsServiceConfigurer(new ClientDetailsServiceBuilder());

    public ClientDetailsServiceConfiguration() {
    }

    @Bean
    public ClientDetailsServiceConfigurer clientDetailsServiceConfigurer() {
        return this.configurer;
    }

    @Bean
    @Lazy
    @Scope(
        proxyMode = ScopedProxyMode.INTERFACES
    )
    public ClientDetailsService clientDetailsService() throws Exception {
        return ((ClientDetailsServiceBuilder)this.configurer.and()).build();
    }
}

ClientDetailsServiceConfigurer:认证客户端配置

public class ClientDetailsServiceConfigurer extends SecurityConfigurerAdapter<ClientDetailsService, ClientDetailsServiceBuilder<?>> {
    public ClientDetailsServiceConfigurer(ClientDetailsServiceBuilder<?> builder) {
        this.setBuilder(builder);
    }

    public ClientDetailsServiceBuilder<?> withClientDetails(ClientDetailsService clientDetailsService) throws Exception {
        this.setBuilder(((ClientDetailsServiceBuilder)this.getBuilder()).clients(clientDetailsService));
        return (ClientDetailsServiceBuilder)this.and();
    }

    public InMemoryClientDetailsServiceBuilder inMemory() throws Exception {
        InMemoryClientDetailsServiceBuilder next = ((ClientDetailsServiceBuilder)this.getBuilder()).inMemory();
        this.setBuilder(next);
        return next;
    }

    public JdbcClientDetailsServiceBuilder jdbc(DataSource dataSource) throws Exception {
        JdbcClientDetailsServiceBuilder next = ((ClientDetailsServiceBuilder)this.getBuilder()).jdbc().dataSource(dataSource);
        this.setBuilder(next);
        return next;
    }

    public void init(ClientDetailsServiceBuilder<?> builder) throws Exception {
    }

    public void configure(ClientDetailsServiceBuilder<?> builder) throws Exception {
    }
}

ClientDetailsServiceBuilder:构造clientDetailsService

public class ClientDetailsServiceBuilder<B extends ClientDetailsServiceBuilder<B>> extends SecurityConfigurerAdapter<ClientDetailsService, B> implements SecurityBuilder<ClientDetailsService> {
    private List<ClientDetailsServiceBuilder<B>.ClientBuilder> clientBuilders = new ArrayList();

    public ClientDetailsServiceBuilder() {
    }

    public InMemoryClientDetailsServiceBuilder inMemory() throws Exception {
        return new InMemoryClientDetailsServiceBuilder();
    }

    public JdbcClientDetailsServiceBuilder jdbc() throws Exception {
        return new JdbcClientDetailsServiceBuilder();
    }

    public ClientDetailsServiceBuilder<?> clients(final ClientDetailsService clientDetailsService) throws Exception {
    public ClientDetailsServiceBuilder<B>.ClientBuilder withClient(String clientId) {
    public ClientDetailsService build() throws Exception {

********************
内部类

    public final class ClientBuilder {
        private final String clientId;
        private Collection<String> authorizedGrantTypes;
        private Collection<String> authorities;
        private Integer accessTokenValiditySeconds;
        private Integer refreshTokenValiditySeconds;
        private Collection<String> scopes;
        private Collection<String> autoApproveScopes;
        private String secret;
        private Set<String> registeredRedirectUris;
        private Set<String> resourceIds;
        private boolean autoApprove;
        private Map<String, Object> additionalInformation;

        public ClientDetailsServiceBuilder<B>.ClientBuilder resourceIds(String... resourceIds) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder redirectUris(String... registeredRedirectUris) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder authorizedGrantTypes(String... authorizedGrantTypes) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder accessTokenValiditySeconds(int accessTokenValiditySeconds) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder refreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder secret(String secret) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder scopes(String... scopes) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder authorities(String... authorities) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder autoApprove(boolean autoApprove) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder autoApprove(String... scopes) {

        public ClientDetailsServiceBuilder<B>.ClientBuilder additionalInformation(Map<String, ?> map) {
        public ClientDetailsServiceBuilder<B>.ClientBuilder additionalInformation(String... pairs) {
            String[] var2 = pairs;
            int var3 = pairs.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                String pair = var2[var4];
                String separator = ":";      //additionalInformation的字符串使用“:”做分隔符
                if (!pair.contains(separator) && pair.contains("=")) {
                    separator = "=";
                }

                int index = pair.indexOf(separator);
                String key = pair.substring(0, index > 0 ? index : pair.length());
                String value = index > 0 ? pair.substring(index + 1) : null;
                this.additionalInformation.put(key, value);
            }

            return this;
        }

        public ClientDetailsServiceBuilder<B> and() {
        private ClientBuilder(String clientId) {
        private ClientDetails build() {

********************

自定义认证服务器

AuthorizationServerConfigurer:认证服务器接口

public interface AuthorizationServerConfigurer {
    void configure(AuthorizationServerSecurityConfigurer var1) throws Exception;

    void configure(ClientDetailsServiceConfigurer var1) throws Exception;

    void configure(AuthorizationServerEndpointsConfigurer var1) throws Exception;
}

AuthorizationServerConfigurerAdapter:认证服务器类

public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer {
    public AuthorizationServerConfigurerAdapter() {
    }

    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    }

    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    }

    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    }
}

AuthorizationServerSecurityConfigurer:认证服务器安全配置

public final class AuthorizationServerSecurityConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
    private AuthenticationEntryPoint authenticationEntryPoint;
    private AccessDeniedHandler accessDeniedHandler = new OAuth2AccessDeniedHandler();
    private PasswordEncoder passwordEncoder;
    private String realm = "oauth2/client";
    private boolean allowFormAuthenticationForClients = false;
    private String tokenKeyAccess = "denyAll()";
    private String checkTokenAccess = "denyAll()";  //使用spring security表达式,默认值为denyAll():拒绝所有请求
                                                      permitAll():允许所有请求
                                                      isAnonymous():是否匿名登陆
                                                      isAuthenticated():不是匿名认证时为true
                                                      isRemberMe():使用remember me认证时为true
                                                      isFullyAuthenticated():是否是全认证,不包含remember me认证
    private boolean sslOnly = false;
    private List<Filter> tokenEndpointAuthenticationFilters = new ArrayList();

    public AuthorizationServerSecurityConfigurer() {
    }

****************
普通方法

    public AuthorizationServerSecurityConfigurer allowFormAuthenticationForClients() {
    public AuthorizationServerSecurityConfigurer tokenKeyAccess(String tokenKeyAccess) {
    public AuthorizationServerSecurityConfigurer checkTokenAccess(String checkTokenAccess) {
    public AuthorizationServerSecurityConfigurer passwordEncoder(PasswordEncoder passwordEncoder) {

    public AuthorizationServerSecurityConfigurer sslOnly() {
    public AuthorizationServerSecurityConfigurer realm(String realm) {
    public AuthorizationServerSecurityConfigurer authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
    public AuthorizationServerSecurityConfigurer accessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {

    public void addTokenEndpointAuthenticationFilter(Filter filter) {
    public void tokenEndpointAuthenticationFilters(List<Filter> filters) {

spring security表达式

public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
    protected final Authentication authentication;
    private AuthenticationTrustResolver trustResolver;
    private RoleHierarchy roleHierarchy;
    private Set<String> roles;
    private String defaultRolePrefix = "ROLE_";
    public final boolean permitAll = true;
    public final boolean denyAll = false;
    private PermissionEvaluator permissionEvaluator;
    public final String read = "read";
    public final String write = "write";
    public final String create = "create";
    public final String delete = "delete";
    public final String admin = "administration";

**************
普通方法

    public final boolean hasAuthority(String authority) {
    public final boolean hasAnyAuthority(String... authorities) {

    public final boolean hasRole(String role) {
    public final boolean hasAnyRole(String... roles) {

    public final boolean permitAll() {
    public final boolean denyAll() {

    public final boolean isAnonymous() {
    public final boolean isAuthenticated() {

    public final boolean isRememberMe() {
    public final boolean isFullyAuthenticated() {

************************

资源服务器配置

*********************

相关注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ResourceServerConfiguration.class})
public @interface EnableResourceServer {
}

*********************

注解导入类

ResourceServerConfiguration:资源服务器配置

@Configuration
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter implements Ordered {
    private int order = 3;

    @Autowired(required = false)
    private TokenStore tokenStore;

    @Autowired(required = false)
    private AuthenticationEventPublisher eventPublisher;

    @Autowired(required = false)
    private Map<String, ResourceServerTokenServices> tokenServices;

    @Autowired
    private ApplicationContext context;

    private List<ResourceServerConfigurer> configurers = Collections.emptyList();

    @Autowired(required = false)
    private AuthorizationServerEndpointsConfiguration endpoints;

    public ResourceServerConfiguration() {

*********************

自定义资源服务器

ResourceServerConfigurer

public interface ResourceServerConfigurer {
    void configure(ResourceServerSecurityConfigurer var1) throws Exception;

    void configure(HttpSecurity var1) throws Exception;
}

ResourceServerConfigurerAdapter

public class ResourceServerConfigurerAdapter implements ResourceServerConfigurer {
    public ResourceServerConfigurerAdapter() {
    }

    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    }

    public void configure(HttpSecurity http) throws Exception {
        ((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
    }
}

ResourceServerSecurityConfigurer:资源服务器安全配置

public final class ResourceServerSecurityConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
    private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
    private AccessDeniedHandler accessDeniedHandler = new OAuth2AccessDeniedHandler();
    private OAuth2AuthenticationProcessingFilter resourcesServerFilter;
    private AuthenticationManager authenticationManager;
    private AuthenticationEventPublisher eventPublisher = null;
    private ResourceServerTokenServices resourceTokenServices;  //设置token编码、解码
    private TokenStore tokenStore = new InMemoryTokenStore();   //token存储,默认存储在内存中
    private String resourceId = "oauth2-resource";
    private SecurityExpressionHandler<FilterInvocation> expressionHandler = new OAuth2WebSecurityExpressionHandler();
    private TokenExtractor tokenExtractor;
    private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
    private boolean stateless = true;

    public ResourceServerSecurityConfigurer() {
        this.resourceId(this.resourceId);
    }

*****************
普通方法

    public ResourceServerSecurityConfigurer authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {

    public ResourceServerSecurityConfigurer accessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
                                            //自定义权限不足时的相关处理

    public ResourceServerSecurityConfigurer tokenStore(TokenStore tokenStore) {
                                            //设置token存储方式

    public ResourceServerSecurityConfigurer resourceId(String resourceId) {
                                            //设置resourceId

    public void configure(HttpSecurity http) throws Exception {

    public ResourceServerSecurityConfigurer eventPublisher(AuthenticationEventPublisher eventPublisher) {
    public ResourceServerSecurityConfigurer expressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
    public ResourceServerSecurityConfigurer tokenExtractor(TokenExtractor tokenExtractor) {
    public ResourceServerSecurityConfigurer authenticationDetailsSource(AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
    public ResourceServerSecurityConfigurer authenticationManager(AuthenticationManager authenticationManager) {
    public ResourceServerSecurityConfigurer tokenServices(ResourceServerTokenServices tokenServices) {

ResourceServerTokenServices

public interface ResourceServerTokenServices {
    OAuth2Authentication loadAuthentication(String var1) throws AuthenticationException, InvalidTokenException;

    OAuth2AccessToken readAccessToken(String var1);
}

RemoteTokenServices

public class RemoteTokenServices implements ResourceServerTokenServices {
    protected final Log logger = LogFactory.getLog(this.getClass());
    private RestOperations restTemplate = new RestTemplate();
    private String checkTokenEndpointUrl;
    private String clientId;
    private String clientSecret;
    private String tokenName = "token";
    private AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();

    public RemoteTokenServices() {

    public void setRestTemplate(RestOperations restTemplate) {
    public void setCheckTokenEndpointUrl(String checkTokenEndpointUrl) {
    public void setClientId(String clientId) {
    public void setClientSecret(String clientSecret) {
    public void setAccessTokenConverter(AccessTokenConverter accessTokenConverter) {
    public void setTokenName(String tokenName) {

    public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
    public OAuth2AccessToken readAccessToken(String accessToken) {

************************

客户端配置

*********************

相关注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({OAuth2ClientConfiguration.class})
public @interface EnableOAuth2Client {
}

*********************

注解导入类

OAuth2ClientConfiguration:oauth2客户端配置

@Configuration
public class OAuth2ClientConfiguration {
    public OAuth2ClientConfiguration() {
    }

    @Bean
    public OAuth2ClientContextFilter oauth2ClientContextFilter() {
        OAuth2ClientContextFilter filter = new OAuth2ClientContextFilter();
        return filter;
    }//存储当前请求和上下文请求

    @Bean
    @Scope(
        value = "request",
        proxyMode = ScopedProxyMode.INTERFACES
    )
    protected AccessTokenRequest accessTokenRequest(@Value("#{request.parameterMap}") Map<String, String[]> parameters, @Value("#{request.getAttribute('currentUri')}") String currentUri) {
        DefaultAccessTokenRequest request = new DefaultAccessTokenRequest(parameters);
        request.setCurrentUri(currentUri);
        return request;
    }//获取accessToken的请求

    @Configuration
    protected static class OAuth2ClientContextConfiguration {
        @Resource
        @Qualifier("accessTokenRequest")
        private AccessTokenRequest accessTokenRequest;

        protected OAuth2ClientContextConfiguration() {
        }

        @Bean
        @Scope(
            value = "session",
            proxyMode = ScopedProxyMode.INTERFACES
        )
        public OAuth2ClientContext oauth2ClientContext() {
            return new DefaultOAuth2ClientContext(this.accessTokenRequest);
        }//session范围内存储token
    }
}

*********************

feign使用oauth2注入bean

ClientCredentialsResourceDetails:设置客户端信息

public class ClientCredentialsResourceDetails extends BaseOAuth2ProtectedResourceDetails {
    public ClientCredentialsResourceDetails() {
        this.setGrantType("client_credentials");
    }

    public boolean isClientOnly() {
        return true;
    }
}

BaseOAuth2ProtectedResourceDetails

public class BaseOAuth2ProtectedResourceDetails implements OAuth2ProtectedResourceDetails {
    private String id;
    private String grantType = "unsupported";
    private String clientId;
    private String accessTokenUri;
    private List<String> scope;
    private String clientSecret;
    private AuthenticationScheme clientAuthenticationScheme;
    private AuthenticationScheme authorizationScheme;
    private String tokenName;

    public BaseOAuth2ProtectedResourceDetails() {

OAuth2FeignRequestInterceptor:feign调用请求拦截器

public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
    public static final String BEARER = "Bearer";
    public static final String AUTHORIZATION = "Authorization";
    private final OAuth2ClientContext oAuth2ClientContext;
    private final OAuth2ProtectedResourceDetails resource;
    private final String tokenType;
    private final String header;
    private AccessTokenProvider accessTokenProvider;

***************
构造方法

    public OAuth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext, OAuth2ProtectedResourceDetails resource) {
    public OAuth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext, OAuth2ProtectedResourceDetails resource, String tokenType, String header) {

***************
普通方法

    public void apply(RequestTemplate template) {
    protected String extract(String tokenType) {
    public OAuth2AccessToken getToken() {
    protected OAuth2AccessToken acquireAccessToken() throws UserRedirectRequiredException {
    public void setAccessTokenProvider(AccessTokenProvider accessTokenProvider) {

OAuth2RestTemplate:oauth2客户端请求操作类

public class OAuth2RestTemplate extends RestTemplate implements OAuth2RestOperations {
    private final OAuth2ProtectedResourceDetails resource;
    private AccessTokenProvider accessTokenProvider;
    private OAuth2ClientContext context;
    private boolean retryBadAccessTokens;
    private OAuth2RequestAuthenticator authenticator;

***************
构造方法

    public OAuth2RestTemplate(OAuth2ProtectedResourceDetails resource) {
    public OAuth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context) {

***************
普通方法

    public void setAuthenticator(OAuth2RequestAuthenticator authenticator) {
    public void setRetryBadAccessTokens(boolean retryBadAccessTokens) {
    public void setErrorHandler(ResponseErrorHandler errorHandler) {
    public OAuth2ProtectedResourceDetails getResource() {
    public OAuth2AccessToken getAccessToken() throws UserRedirectRequiredException {
    public OAuth2ClientContext getOAuth2ClientContext() {
    public void setAccessTokenProvider(AccessTokenProvider accessTokenProvider) {
发布了331 篇原创文章 · 获赞 92 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43931625/article/details/104119482