如何使用 Spring 通过 OAuth2 保护 MVC 应用程序?

How to secure a MVC application with OAuth2 using Spring?

对不起,我的英语。

我有一个可以用通常方式登录的应用程序。

@Configuration
@EnableWebSecurity
public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        System.out.println("LoginSecurityConfig :: configure");

        auth.jdbcAuthentication().dataSource( getDataSource() )
            .passwordEncoder( new BCryptPasswordEncoder(16) )
            .usersByUsernameQuery(
                "select user_name as username,password,enabled from users where user_name=?")
            .authoritiesByUsernameQuery(
                "select user_name as username, role_name from users_roles ur join users u on ur.user_id = u.user_id and u.user_name = ?");

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


        http
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/login*").anonymous()
        .antMatchers("/resources/**").permitAll()
        .antMatchers("/fotos/**").permitAll()
        .antMatchers("/users").access("hasRole('ROLE_ADMIN')")
        .antMatchers("/user").access("hasRole('ROLE_ADMIN')")
        .anyRequest().authenticated()
        .and()

        .formLogin()
        .loginPage("/loginPage")
        .defaultSuccessUrl("/home", true)
        .failureUrl("/loginPage?error=true")
        .loginProcessingUrl("/login")
        .usernameParameter("username")
        .passwordParameter("password")
        .and()

        .logout()
        .logoutSuccessUrl("/loginPage")
        .invalidateHttpSession(true); 



    }    

}

使用这个我可以尝试访问任何安全资源,系统将我发送到 loginPage,在那里我可以 post usernamepassword 到内部 login 控制器然后我有 Principal 并且可以访问受保护的资源(家庭、用户、用户)。工作正常。

但是...我需要删除用户控制数据库内容并使用 OAuth2 来允许相同类型的访问。我不想再在我的数据库中有任何用户。我需要一个登录屏幕,然后是一个令牌请求,例如 http://myserver/oauth/token?grant_type=password&username=admin&password=adminBasic 中传递 client_idclient_secret。我知道如何做 "get token" 部分,我的服务器工作正常,给我令牌和刷新令牌,但只使用 Postman,因为我不知道如何在我的 Web 应用程序代码中使用它。我发现的所有教程都在同一应用程序中同时使用服务器和客户端,实际上并没有展示如何使用 OAuth2 远程服务器。

已经尝试使用 this。这是一个很好的教程,非常接近我的需要,但对我来说太复杂了。

我有这段代码并且知道它可以使用服务器并使用客户端凭据颁发令牌,但不知道如何为用户提供登录屏幕并获取他的凭据来完成请求(GET部分)。

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfigRemoteTokenService extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(final HttpSecurity http) throws Exception {
                http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                    .and()
                    .authorizeRequests().anyRequest().permitAll();              
    }

    @Primary
    @Bean
    public RemoteTokenServices tokenServices() {
        final RemoteTokenServices tokenService = new RemoteTokenServices();
        tokenService.setCheckTokenEndpointUrl("http://myoauthserver/oauth/check_token");
        tokenService.setClientId("clientid");
        tokenService.setClientSecret("password");
        return tokenService;
    }

}

所以...我如何保护我的系统,从用户那里获取登录名和密码并使用此代码来控制凭据,就像我使用通常的数据库方法一样?

或者 OAuth2 仅用于安全 REST API?

请新手友好,因为我不太习惯使用 Spring。

我最近一直在研究这个问题,我希望我能说我有一个简单的答案,但我没有。我必须先问这样的问题,这是 Web 应用程序(JSP 等)还是 Web 应用程序使用的 REST API,还是移动应用程序使用的 REST API等等等等

这很重要的原因是您首先必须 select OAuth2 配置文件和授权类型之一,它们在 Spring 中都有不同的要求和配置。

此外,您是否正在尝试与第三方 OAuth2 身份验证提供程序(例如 Facebook)集成,或者您的应用程序是否同时充当身份验证提供程序(进行登录和密码验证)和受保护资源(网页所在位置)请求或 API 呼叫转到)?

所以我想我能做的最好的就是给你布置一些作业:

(1) 阅读各种 OAuth2 配置文件并确定最适合您的应用程序的配置文件,并学习所有术语(例如,什么是客户端机密?)。

这绝对不是您可以在不理解示例代码的情况下剪切和粘贴示例代码的情况。如果您对 OAuth2 的工作原理没有合理的理解,您将会遇到很多困难。

另外:我们在这里谈论的是安全,所以在不理解的情况下做事是一个非常糟糕的主意。如果您不小心,您可能认为它在起作用,但实际上您让自己容易受到攻击。

(2) 如果您不熟悉 Spring Framework Security,您需要具备基本的基础才能理解您在做什么。

(3) 一旦您确定了要使用的配置文件,就可以在 google 搜索中使用它,例如“Spring oauth2 implicit grant” 以查找为该配置文件量身定制的示例。

那里有一些,这是一个很好的起点,尽管我发现我无法将任何示例直接用于我的应用程序,因为它们的假设和我的应用程序存在细微差别。

Spring 参考指南也很有帮助,但不一定提供您可能遇到的所有问题的所有详细信息。最后,尝试用你的应用程序来实现。

您需要一些好的工具来向您的应用程序发送请求(为此我喜欢 PostMan),这样您就可以检查来回的数据。 OAuth2 涉及一系列复杂的 HTTP 重定向,因此测试可能有点困难。

此外,请耐心等待。我认为自己是 Spring 专家,但我仍然花了几天时间才让事情完全按照我想要的方式进行。请注意,实际上您最终编写的代码非常少,但是要完全正确地编写少量代码才是困难的。

简单如 1,2,3 ...

只需更改我的 OAuth2 服务器以接受 oauth/authorize 方法。

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
        .requestMatchers()
        .antMatchers("/login", "/oauth/authorize")
    .and()
        .authorizeRequests()
        .anyRequest()
        .authenticated()
    .and()
        .formLogin()
        .permitAll();       
}

并创建自定义登录表单。现在所有客户端(Web 应用程序)都可以登录了。

您可以在此处找到示例客户端和更多详细信息:http://www.baeldung.com/sso-spring-security-oauth2

您还可以在我的 github 存储库中检查我的整个服务器和客户端:

https://github.com/icemagno/geoinfra/cerberus

https://github.com/icemagno/geoinfra/atlas

在pt_BR