Веб-и мобильные клиенты для Spring Безопасность OAuth2

Я пытаюсь обернуть голову вокруг OAuth2 и Spring Security OAuth, особенно для службы OAuth Provider. Я пытаюсь реализовать следующее:

  • Поставщик OAuth
  • Сервер ресурсов (веб-службы RESTful, которые должны быть защищены с использованием OAuth Provider (1))
  • Веб-клиент (приложение веб-клиента, защищенное с помощью Spring Безопасность, но должно использовать OAuth Provider (1) для аутентификации пользователя
  • Собственные мобильные клиенты (Android и iOS), которые также должны использовать OAuth Provider (1) для аутентификации

Все эти модули независимы друг от друга, т.е. разделены в разных проектах и ​​будут размещаться в разных доменах, таких как (1) http://oauth.web.com, (2) http://rest.web.com, (3) http://web.com

Мои два вопроса:

а. Как реализовать проект веб-клиента, чтобы при входе пользователя на защищенную страницу или нажатии кнопки "Войти", перенаправление на URL-адрес провайдера OAuth, вход в систему и аутентификация на веб-клиенте со всеми ролями пользователя, а также нужно знать, какой клиент был использован. @EnableResourceServer (так же, как реализован Resource Server, см. код ниже) в этом проекте, чтобы получить информацию о пользователе? Нужно ли мне управлять токеном доступа и всегда включать его в вызов на сервере ресурсов или это можно сделать как-то автоматически?

В. Каков наилучший способ обеспечения безопасности в мобильных приложениях, которые я буду разрабатывать. Должен ли я использовать пароль grand для этой аутентификации, так как приложения будут созданы мной, где у меня будет имя пользователя и пароль на собственном экране, а затем отправьте на сервер в качестве базовой проверки подлинности через SSL? Есть ли какие-либо образцы, на которых я могу взглянуть на этот разговор с Spring Security OAuth и вернуть данные пользователя.

Вот моя реализация проекта OAuth (1) и ресурсного проекта (2):

1. Поставщик OAuth

Конфигурации сервера OAuth2 (большая часть кода была взята из ЗДЕСЬ)

@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();
    }
}

UserDetailsService (customUserDetailsService)

@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)

Конфигурация (большая часть кода скелета взята из ЭТО)

@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
}

Ответы

Ответ 1

Как реализовать проект веб-клиента, чтобы при регистрации пользователя на защищенной странице или нажимает кнопку "Войти", перенаправляется на URL-адрес провайдера OAuth, войти в систему и пройти аутентификацию на веб-клиенте со всеми ролями пользователей, а также также необходимо знать, какой клиент был используется

Вы хотите использовать OAuth как SSO.

Вариант 1, используйте spring облако https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v

Вариант 2 вручную обрабатывает процесс SSO:

в вашем веб-клиенте, настройте страницу входа на сервер 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. ваш веб-клиент должен обмениваться этим кодом с доступом к токенам на вашем сервере oauth. На сервере oauth создайте конечную точку для получения информации о пользователе

@RestController
public class UserRestService {

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

}

Затем ваш веб-клиент может получить доступ к информации сведений о пользователях, отправив запрос с доступом к токенам к вышеуказанной конечной точке отдыха и аутентифицировать пользователя на основе ответа.

Нужно ли мне управлять маркером доступа и всегда включать его в вызов сервер ресурсов или это может быть сделано как-то автоматически?

Каждый запрос должен включать доступ к токену. Если вы хотите сделать это автоматически, spring предоставит клиент Oauth 2 http://projects.spring.io/spring-security-oauth/docs/oauth2.html

Каков наилучший способ обеспечения безопасности в мобильных приложениях, которые Я буду развиваться. Должен ли я использовать пароль grand для этого аутентификации, поскольку приложения будут созданы мной, где у меня будет имя пользователя и пароль должны быть на собственном экране, а затем отправляться на сервер в качестве базовой проверки подлинности через SSL?

Поскольку вы используете собственный экран, достаточно предоставить пароль, но вы можете сохранить токен обновления, это позволит вам запрашивать доступ к токену без повторения процесса аутентификации.

Есть ли какие-то образцы, которые я могу посмотреть на этот разговор с SpringБезопасность OAuth и вернуть данные пользователя.

см. пример кода выше или взгляните на это https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v