swagger 无法访问 OAuth2

Posted

技术标签:

【中文标题】swagger 无法访问 OAuth2【英文标题】:OAuth2 is not accessible from swagger 【发布时间】:2019-03-25 04:20:04 【问题描述】:

当我尝试从 swagger 访问 OAuth2 时收到 401。如果 Swagger 在同一个项目中配置并在同一个端口上运行,它工作正常。但是当我在另一个具有不同端口的项目中配置 swagger 时,它会给出 401。

OAuth2 可以访问并且可以与 Postman 一起正常工作。我无法找到为什么它从不同的端口给出 401。我检查了正在运行的端口的入站/出站规则。从不同的服务器或端口访问 OAuth 是否需要任何其他配置?

OAuth2 项目配置在http://localhost:8090/ SpringBoot 项目在http://localhost:8888/ 上配置,OAuth2 提供 401。

网络安全配置

@Configuration
@EnableWebSecurity
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter 
    @Lazy
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception 
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    

    @Override
    public void configure(HttpSecurity http) throws Exception 
        http
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .antMatchers("/oauth/**").permitAll()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .httpBasic()
                .and()
                .csrf().disable();
    
    /*
     * https://github.com/spring-projects/spring-boot/issues/11136
     * Expose it manually (there is bug)
     *
     * */


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

授权服务器配置:

@Configuration
@EnableAuthorizationServer
public class CustomAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter 

    private static final String CLIENT_ID = "client";
    private static final String CLIENT_SECRET = "secret";
    private static final String GRANT_TYPE_PASSWORD = "password";
    private static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
    private static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
    private static final String GRANT_TYPE_AUTH_CODE = "authorization_code";

    private static final String SCOPE_READ = "read";
    private static final String SCOPE_WRITE = "write";
    private static final String SCOPE_TRUST = "trust";

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private CustomUserDetailService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Value("$config.oauth2.tokenTimeout")
    private int ACCESS_TOKEN_VALIDITY_SECONDS;

    @Value("$config.oauth2.tokenTimeout")
    private int REFRESH_TOKEN_VALIDITY_SECONDS;

    @Value("$config.oauth2.privateKey")
    private String privateKey;

    @Value("$config.oauth2.publicKey")
    private String publicKey;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
        clients
                .inMemory()
                .withClient(CLIENT_ID)
                .authorizedGrantTypes(GRANT_TYPE_CLIENT_CREDENTIALS, GRANT_TYPE_PASSWORD, GRANT_TYPE_REFRESH_TOKEN, GRANT_TYPE_AUTH_CODE)
                .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
                .scopes(SCOPE_READ, SCOPE_WRITE, SCOPE_TRUST)
                .resourceIds("oauth2-resource")
                .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
                .refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS)
                .secret(passwordEncoder.encode(CLIENT_SECRET));
    


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
        endpoints.authenticationManager(authenticationManager)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
                .tokenStore(tokenStore())
                .userDetailsService(userDetailsService)
                .tokenServices(tokenServices())
                .accessTokenConverter(accessTokenConverter());
    

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() 
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(privateKey);

        return converter;
    

    @Bean
    public JwtTokenStore tokenStore() 
        return new JwtTokenStore(accessTokenConverter());
    

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() 
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setTokenEnhancer(accessTokenConverter());
        return defaultTokenServices;
    

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception 
        security.checkTokenAccess("isAuthenticated()")
                .tokenKeyAccess("permitAll()");
    

WebSecureConfigurerAdapter:

@Configuration
@EnableResourceServer
public class CustomResourceConfig extends ResourceServerConfigurerAdapter     
    @Value("$config.oauth2.publicKey")
    private String publicKey;

    @Value("$config.oauth2.privateKey")
    private String privateKey;

    @Value("$config.oauth2.resource.id")
    private String resourceId;

    @Override
    public void configure(HttpSecurity http) throws Exception 
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS).authenticated()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .antMatchers("/", "/home", "/register", "/login").permitAll()
                .antMatchers("/oauth/**").authenticated();

    

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) 
        resources
                .resourceId(resourceId)
                .tokenServices(tokenServices())
                .tokenStore(tokenStore());
    

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() 
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setTokenEnhancer(accessTokenConverter());
        return defaultTokenServices;
    


    @Bean
    public JwtAccessTokenConverter accessTokenConverter() 
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(privateKey);
        return converter;
    

    @Bean
    public JwtTokenStore tokenStore() 
        return new JwtTokenStore(accessTokenConverter());
    

【问题讨论】:

也许项目需要一些 Cors 配置? 【参考方案1】:

在 Swagger 配置中,应在创建 Docket 实例时正确初始化 OAuth 安全架构。这里的访问令牌 URI 类似于:http://localhost:8080/api/oauth/token

@Value("$config.oauth2.accessTokenUri")
private String accessTokenUri;


@Bean
public Docket productApi() 
return new Docket(DocumentationType.SWAGGER_2)
                .select().apis(RequestHandlerSelectors.basePackage("com.authentication")).paths(regex("/.*"))
                .paths(PathSelectors.any())
                .build()
                .securityContexts(Collections.singletonList(securityContext()))
                .securitySchemes(Arrays.asList(securitySchema()))
                .apiInfo(apiInfo());

private OAuth securitySchema() 

    List<AuthorizationScope> authorizationScopeList = newArrayList();
    authorizationScopeList.add(new AuthorizationScope("read", "read all"));
    authorizationScopeList.add(new AuthorizationScope("write", "access all"));

    List<GrantType> grantTypes = newArrayList();
    GrantType passwordCredentialsGrant = new ResourceOwnerPasswordCredentialsGrant(accessTokenUri);
    grantTypes.add(passwordCredentialsGrant);

    return new OAuth("oauth2", authorizationScopeList, grantTypes);


private SecurityContext securityContext() 
    return SecurityContext.builder().securityReferences(defaultAuth())
            .build();

【讨论】:

以上是关于swagger 无法访问 OAuth2的主要内容,如果未能解决你的问题,请参考以下文章

解决 Nginx 部署,无法访问 Swagger 文档的问题

解决 Nginx 部署,无法访问 Swagger 文档的问题

springboot 集成swagger2 404 无法访问

无法检索 oauth2 的访问令牌

Spring Boot Security - 如果用户未通过 Oauth2 进行身份验证,如何禁用对 swagger ui 页面的端点的访问

使用 oauth2 休息服务:无法找到令牌的访问令牌