java - Spring Security OAuth2 的 Web 和移动客户端

标签 java spring oauth spring-security spring-security-oauth2

我正在尝试围绕 OAuth2 和 Spring Security OAuth,尤其是 OAuth Provider 服务。我正在尝试实现以下内容:

  1. OAuth 提供者
  2. 资源服务器(应使用 OAuth Provider 保护的 RESTful Web 服务 (1))
  3. Web 客户端(使用 Spring Security 保护但应使用 OAuth Provider (1) 对用户进行身份验证的 Web 客户端应用程序
  4. 也应使用 OAuth Provider (1) 进行身份验证的本地移动客户端(Android 和 iOS)

所有这些模块都是相互独立的,即分开在不同的项目中,并将托管在不同的域上,例如(1)http://oauth.web.com , (2) http://rest.web.com , (3) http://web.com

我的两个问题是:

A.如何实现 Web 客户端项目,以便当用户在 protected 页面上登录或单击“登录”按钮时,重定向到 OAuth Provider url,登录,并在具有所有用户角色的 Web 客户端上进行身份验证,以及需要知道使用了哪个客户端。 @EnableResourceServer(与 Resource Server 的实现方式相同;请参见下面的代码)在此项目中获取用户的详细信息?我是否必须管理访问 token 并始终将其包含在对资源服务器的调用中,或者它可以以某种方式自动完成?

B.在我将要开发的移动应用程序上实现安全性的最佳方法是什么。我是否应该为此身份验证使用密码大,因为应用程序将由我构建,我将在 native 屏幕中拥有用户名和密码,然后作为通过 SSL 的基本身份验证发送到服务器?是否有任何示例可以让我查看与 Spring Security OAuth 的对话并返回用户详细信息。

这是我对 OAuth 项目 (1) 和资源项目 (2) 的实现:

1。 OAuth 提供者

OAuth2 服务器配置(大部分代码取自 HERE)

@Configuration
@EnableAuthorizationServer
public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    DataSource dataSource;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .tokenStore(tokenStore())
                .approvalStore(approvalStore())
                .authorizationCodeServices(authorizationCodeServices())
        ;
    }

    @Bean
    public JdbcClientDetailsService clientDetailsService() {
        return new JdbcClientDetailsService(dataSource);
    }

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

    @Bean
    public ApprovalStore approvalStore() {
        return new JdbcApprovalStore(dataSource);
    }

    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {

        oauthServer.checkTokenAccess("permitAll()");
    }
}

网络安全配置

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

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

        http.csrf().disable(); // TODO. Enable this!!!

        http.authorizeRequests()
                .and()
                .formLogin()
//                .loginPage("/login") // manually defining page to login
//                .failureUrl("/login?error") // manually defining page for login error
                .usernameParameter("email")
                .permitAll()

                .and()
                .logout()
//                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
                .permitAll();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(customUserDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }

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

用户详细信息服务(customUserDetailsS​​ervice)

@Service
public class CustomUserDetailsService implements UserDetailsService{

    private final UserService userService;

    @Autowired
    public CustomUserDetailsService(UserService userService) {
        this.userService = userService;
    }

    public Authority loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userService.getByEmail(email)
                .orElseThrow(() -> new UsernameNotFoundException(String.format("User with email=%s was not found", email)));
        return new Authority(user);
    }
}

2。资源服务器(RESTful WS)

配置(大部分框架代码取自 THIS 示例)

@Configuration
@EnableResourceServer
public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter{

    @Autowired
    DataSource dataSource;

    String RESOURCE_ID = "data_resource";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        TokenStore tokenStore = new JdbcTokenStore(dataSource);
        resources
                .resourceId(RESOURCE_ID)
                .tokenStore(tokenStore);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                // For some reason we cant just "permitAll" OPTIONS requests which are needed for CORS support. Spring Security
                // will respond with an HTTP 401 nonetheless.
                // So we just put all other requests types under OAuth control and exclude OPTIONS.
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
                .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')")
                .and()

                // Add headers required for CORS requests.
                .headers().addHeaderWriter((request, response) -> {
            response.addHeader("Access-Control-Allow-Origin", "*");

            if (request.getMethod().equals("OPTIONS")) {
                response.setHeader("Access-Control-Allow-Methods", request.getHeader("Access-Control-Request-Method"));
                response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
            }
        });    
    }
}

WS Controller :

@RestController
@RequestMapping(value = "/todos")
public class TodoController {

    @Autowired
    private TodoRepository todoRepository;

    @RequestMapping(method = RequestMethod.GET)
    public List<Todo> todos() {
        return todoRepository.findAll();
    }

   // other methods
}

最佳答案

How do I implement a Web Client project so that when user is logging in on the protected page or clicks on the Login button, be redirected to OAuth Provider url, login, and be authenticated on the Web Client with all user roles and also as well need to know which client was used

您想将 OAuth 用作 SSO。

选项1,使用spring cloud https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v

方案2,手动处理SSO流程:

在您的 Web 客户端中,使用授权授权将登录页面配置到 OAuth 服务器。

protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable(); // TODO. Enable this!!!
    http.authorizeRequests()
    .and()
    .formLogin()
    .loginPage("http://oauth.web.com/oauth/authorize?response_type=code&client_id=webclient&redirect_uri=http://web.com") // manually defining page to login
    //.failureUrl("/login?error") // manually defining page for login error
    .usernameParameter("email")
    .permitAll()   
    .and()
    .logout()
    //.logoutUrl("/logout")
    .logoutSuccessUrl("/")
    .permitAll();
}

身份验证和授权过程完成后,您将被重定向到带有授权代码http://web.com/?code=jYWioI的Web客户端。您的 Web 客户端应将此代码与您的 oauth 服务器上的 token 访问交换。 在您的 oauth 服务器上,创建用于检索用户信息的端点

@RestController
public class UserRestService {

  @RequestMapping("/user")
  public Principal user(Principal user) {
    // you can also return User object with it's roles
    // {"details":...,"principal":{"username":"user",...},"name":"user"}
    return user;
  }

}

然后,您的 Web 客户端可以通过向上述 rest 端点发送带有 token 访问权限的请求来访问用户详细信息,并根据响应对用户进行身份验证。

Do I have to manage Access Token and always include it in the call to the Resource Server or it can be done somehow automatically?

每个请求都必须包含 token 访问权限。如果要自动执行,spring 提供了 Oauth 2 客户端 http://projects.spring.io/spring-security-oauth/docs/oauth2.html

What is the best way to implement security on the mobile apps that I'll be developing. Should I be using password grand for this authentication, since the apps will be build by me where I'll have a user name and password be in the native screen and then be send to the server as a basic authentication over SSL?

由于您使用的是原生屏幕,密码授权就足够了,但您可以存储刷新 token ,这将使您无需重复身份验证过程即可请求 token 访问。

Are there any samples that I can take a look at that talk to Spring Security OAuth and return user details.

查看上面的示例代码或查看此 https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v

关于java - Spring Security OAuth2 的 Web 和移动客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31970206/

相关文章:

python - 在 Python 中生成随机数的标准方法是什么?

java - 如何使用 Smack 更改自己的名字?

java - 准备语句根据记录中的另一个值更新一个值

java - 如何在 Hibernate 不生成任何表的情况下使用 Hibernate Envers (@Audited)

java - 在已有的类中实现 Spring 事务处理

java - 使用来自 angular4 的 @RequestPart 在一个请求中发布多部分文件和 json

java - Java 中的通配符不适用于 Spark cogroup 函数

java - 调试 war 文件中特定 jar 文件的包含情况

java - Oauth2 Spring 实现

php - 将 OAuth 或公钥 API 用于私有(private) YouTube 应用程序?