【问题标题】:Web and Mobile Clients for Spring Security OAuth2Spring Security OAuth2 的 Web 和移动客户端
【发布时间】:2015-11-05 08:34:18
【问题描述】:

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

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

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

我的两个问题是:

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

B.在我将要开发的移动应用程序上实施安全性的最佳方法是什么。我是否应该为此身份验证使用密码大,因为应用程序将由我构建,我将在本机屏幕中拥有用户名和密码,然后作为通过 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 控制器:

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

    @Autowired
    private TodoRepository todoRepository;

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

   // other methods
}

【问题讨论】:

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


    【解决方案1】:

    如何实现 Web 客户端项目,以便在用户登录时 在受保护的页面上或单击登录按钮,被重定向 到 OAuth Provider url,登录并在 Web 客户端上进行身份验证 具有所有用户角色,并且还需要知道哪个客户端是 用过

    您想将 OAuth 用作 SSO。

    方案一,使用spring cloudhttps://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 服务器上的令牌访问交换。 在您的 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 端点发送带有令牌访问权限的请求来访问用户详细信息,并根据响应对用户进行身份验证。

    我是否必须管理访问令牌并始终将其包含在对 资源服务器还是可以自动完成?

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

    在移动应用上实施安全性的最佳方式是什么? 我会发展的。我应该为此使用密码吗 身份验证,因为应用程序将由我构建,在那里我将拥有一个 用户名和密码在本机屏幕上,然后发送到 服务器作为基于 SSL 的基本身份验证?

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

    有没有什么样本可以看一下与 Spring 的谈话 安全 OAuth 并返回用户详细信息。

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

    【讨论】:

    • 感谢您的回答。我一直在研究同样的问题。但是我在这部分卡住了“您的 Web 客户端应该将此代码与您的 oauth 服务器上的令牌访问交换。在您的 oauth 服务器上,创建一个用于检索用户信息的端点。”什么端点——假设我有一个像你链接的博客文章这样的设置,我的客户应该使用什么?我没有成功,也没有看到 Spring 提供的具有实际端点工作流程的良好文档。
    • @adeady 在您的 Web 客户端创建服务,将代码发布到 /oauth/token 端点,这将为您提供令牌。您获得的 oauth 令牌可用于访问受保护的资源。
    猜你喜欢
    • 2012-10-22
    • 2013-06-20
    • 2021-03-07
    • 2022-11-08
    • 2019-04-06
    • 2017-09-17
    • 2020-02-11
    • 1970-01-01
    • 2019-07-20
    相关资源
    最近更新 更多