当前位置: 首页 > 知识库问答 >
问题:

Spring boot Oauth2 -授权和资源服务器之间的安全不兼容

谭浩皛
2023-03-14

我正在尝试使用Spring构建一个OAuth2授权服务器。问题是我无法让它与登录和授权表单以及资源服务器一起使用oAuth2令牌检索用户数据。

这是我的主要配置,除了用户服务和存储库...

网络安全配置

@EnableWebSecurity
@Configuration
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource(name = "userService")
    private UserDetailsService userDetailsService;

    @Autowired
    private ClientDetailsService clientDetailsService;

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

    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(encoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login", "/oauth/authorize").permitAll()
                .and()
                .formLogin().permitAll();
    }

    @Bean
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }

    @Bean
    public BCryptPasswordEncoder encoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }
}

授权服务器配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private Environment env;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;

    @Value("classpath:schema.sql")
    private Resource schemaScript;

    @Value("classpath:data.sql")
    private Resource dataScript;

    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
        configurer.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .tokenStore(tokenStore)
                .userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager);
    }

    @Override
    public void configure(final AuthorizationServerSecurityConfigurer oauthServer) {
        oauthServer
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()");
    }

    @Bean
    public DataSourceInitializer dataSourceInitializer() {
        final DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDataSource(dataSource);
        initializer.setDatabasePopulator(databasePopulator());
        return initializer;
    }

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource());
    }

    @Bean
    public ClientCredentialsTokenEndpointFilter checkTokenEndpointFilter() {
        ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter("/oauth/check_token");
        filter.setAuthenticationManager(authenticationManager);
        filter.setAllowOnlyPost(true);
        return filter;
    }


    private DatabasePopulator databasePopulator() {
        final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScript(schemaScript);
        populator.addScript(dataScript);
        return populator;
    }

    private DataSource dataSource() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("spring.datasource.driverClassName"));
        dataSource.setUrl(env.getProperty("spring.datasource.url"));
        dataSource.setUsername(env.getProperty("spring.datasource.username"));
        dataSource.setPassword(env.getProperty("spring.datasource.password"));
        return dataSource;
    }
}

资源服务器配置

@Configuration
@EnableResourceServer
@Order(3)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "resource_id";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID).stateless(false);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/user").authenticated()
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}

用户控制

@Controller
public class UserController {

    @Autowired
    UserService userService;

    @PreAuthorize("#oauth2.hasScope('read_user_profile')")
    @GetMapping("/user")
    @ResponseBody
    public Optional<User> getUser(@RequestParam String email) {
        return userService.findAll().stream().filter(x -> x.getEmail().equals(email)).findAny();
    }

    @PostMapping(value = "/user", consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.CREATED)
    public void postMessage(@RequestBody User user) {
        userService.save(user);
    }

}

正如你所看到的,我给他们下了订单。问题是,如果WebSecurityConfig是第一个,我可以进入/login和/oauth/authorize屏幕,但用户控制器没有任何安全层,并且它是打开的(不需要令牌):S

如果顺序相反,我看不到登录页面,但我看到了404。顺便说一句,它从 /oauth/authorize重定向。但是我可以使用生成的令牌访问用户控制器。

我做错了什么?不可能在同一个模块中同时拥有两者吗?

共有1个答案

金子平
2023-03-14

我认为这不是‘顺序’的问题。

@PreAuthorize注解由方法安全性使用。如果您想让它工作,您需要@EnableGlobalMethod odSecurity(prePostEnilly=true)注解。

但是,如果您只想通过OAuth保护您的资源,为什么不在ResourceServerConfig上使用url base安全约束进行配置呢?

例如,我的ResourceServerConfig工作正常,如下所示:

    @Override
    public void configure(HttpSecurity http) throws Exception {
         http.antMatcher("/api/**")
            .authorizeRequests()
            .antMatchers(HttpMethod.GET, "/user").access("#oauth2.hasScope('read')");
    }
 类似资料:
  • 我有以下场景:一个客户端应用程序试图访问API网关后面的APIendpoint。我想验证(使用id和秘密)应用程序,如果它是应用程序A允许它访问endpoint/信用,如果它是应用程序B允许它访问endpoint/借方。 我假设API网关应该验证一个调用是否应该被拒绝。你能告诉我我的工作流应该是什么样子,我应该使用什么Keycloak功能吗?

  • 我需要了解在我的项目范围内使用autheorizaion服务器的便利性。 我们正在实现我们的服务并将其部署到客户环境中。 客户基础结构已经提供了一种身份验证机制,以便对用户进行身份验证。 此机制拦截所有通信并将用户重定向到“登录”表单。 之后,用户被重定向到我们的服务,我们必须处理和消化它,并使用JWT令牌进行响应。 这是我感到迷茫的地方: 我在想: 使用Spring oauth2 向授权服务器请

  • 有两个< code >Spring启动应用程序。 有用作 dev okta 帐户 (这两个应用程序是标准的< code>Spring Boot客户端- -安全地将消息发送到-- (它按预期工作) 但我试图弄清楚他们之间发生了什么,交通明智 我试图发现检查它从从获取的令牌的那一刻。 这是标准< code>oauth 2.0流程和我想调试部分的序列图(箭头) 之间有一个通信,器: 我似乎无法确认资源服

  • 我们正在开发一个微服务架构中的应用程序,该应用程序在多个OAuth2提供商(如Google和Facebook)上使用Spring Cloud OAuth2实现登录。我们还在开发自己的授权服务器,并将在下一个版本中集成。 现在,在我们的微服务(即资源服务器)上,我想知道如何处理多个< code>token-info-uri或< code>user-info-uri到多个授权服务器(例如脸书或谷歌)。

  • 我正在使用以下内容: Spring 4.2 Spring security 4.0.2 Spring oauth2 2.0.7 null 资源服务器配置似乎不限于/rest/**,而是覆盖了所有的安全配置。即对受保护的非OAuth资源的调用不受保护(即筛选器没有捕获它们并重定向到登录)。 配置(为了简单起见,我删除了一些内容):

  • 现在,我了解了访问令牌和刷新令牌,但我不知道如何实现它。 我有一个项目,前端是棱角分明的,后端是node.js的,前面有微服务架构和网关。我可以使用像oaust2授权服务器一样的aust0,用户存储在里面? 怎么做?在aust0文档中有大量的说明,我不明白哪个适合我。 我必须通过网关拦截登录、注销和注册,并重定向到auth0,或者我必须在我的用户微服务内部完成这些操作? 在我的项目中,还有个人信息