Форум программистов, компьютерный форум, киберфорум
Java EE (J2EE)
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.95/21: Рейтинг темы: голосов - 21, средняя оценка - 4.95
102 / 102 / 40
Регистрация: 24.01.2014
Сообщений: 1,244
1

Oauth2 authentication with spring security

20.01.2017, 16:56. Показов 3973. Ответов 8
Метки нет (Все метки)

Доброго времени суток, я пытаюсь сделать на своем сайте авторизацию с помощью других сервисов. На данный момент есть google, facebook и vk. С google все работает отлично, facebook присылает в ответ почему-то только имя пользователя, в том время как vk ничего вообще не присылает, подскажите, как получать данные о пользователях с facebook и vk ?

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package spring.hotel.config;
 
@SpringBootApplication
@Controller
public class Application {
    @Autowired
    private OAuth2ClientContext oauth2ClientContext;
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
 
    @Bean
    public OAuth2ClientContext oAuth2ClientContext(){
        return oauth2ClientContext;
    }
 
    @RequestMapping(value = {"/"}, method = RequestMethod.GET)
    public String defaultPage() {
        return "index";
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
@Configuration
@EnableWebSecurity
@EnableOAuth2Client
@EnableAuthorizationServer
@ComponentScan(value = "spring.hotel")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    OAuth2ClientContext oauth2ClientContext;
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**").permitAll().anyRequest()
                .authenticated().and().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"))
                .and().logout().logoutSuccessUrl("/").permitAll().and().csrf().csrfTokenRepository(csrfTokenRepository()).and()
                .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
                .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
    }
 
    @Bean
    @ConfigurationProperties("facebook.client")
    public AuthorizationCodeResourceDetails facebook() {
        return new AuthorizationCodeResourceDetails();
    }
 
    @Bean
    @ConfigurationProperties("facebook.resource")
    public ResourceServerProperties facebookResource() {
        return new ResourceServerProperties();
    }
 
    @Bean
    @ConfigurationProperties("google.client")
    public AuthorizationCodeResourceDetails google() {
        return new AuthorizationCodeResourceDetails();
    }
 
    @Bean
    @ConfigurationProperties("google.resource")
    public ResourceServerProperties googleResource() {
        return new ResourceServerProperties();
    }
 
    @Bean
    @ConfigurationProperties("vk.client")
    public AuthorizationCodeResourceDetails vk() {
        return new AuthorizationCodeResourceDetails();
    }
 
    @Bean
    @ConfigurationProperties("vk.resource")
    public ResourceServerProperties vkResource() {
        return new ResourceServerProperties();
    }
 
    @Bean
    public FilterRegistrationBean oauth2ClientFilterRegistration(
            OAuth2ClientContextFilter filter) {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(filter);
        registration.setOrder(-100);
        return registration;
    }
 
    private Filter csrfHeaderFilter() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                    throws ServletException, IOException {
                CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
                if (csrf != null) {
                    Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                    String token = csrf.getToken();
                    if (cookie == null || token != null && !token.equals(cookie.getValue())) {
                        cookie = new Cookie("XSRF-TOKEN", token);
                        cookie.setPath("/");
                        response.addCookie(cookie);
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }
 
    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }
 
    private Filter ssoFilter() {
        CompositeFilter filter = new CompositeFilter();
        List<Filter> filters = new ArrayList<Filter>();
 
        OAuth2ClientAuthenticationProcessingFilter facebookFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/facebook");
        OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(facebook(), oauth2ClientContext);
        facebookFilter.setRestTemplate(facebookTemplate);
        UserInfoTokenServices tokenServices = new UserInfoTokenServices(facebookResource().getUserInfoUri(), facebook().getClientId());
        tokenServices.setRestTemplate(facebookTemplate);
        facebookFilter.setTokenServices(tokenServices);
        filters.add(facebookFilter);
 
        OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/google");
        OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(google(), oauth2ClientContext);
        googleFilter.setRestTemplate(googleTemplate);
        tokenServices = new UserInfoTokenServices(googleResource().getUserInfoUri(), google().getClientId());
        tokenServices.setRestTemplate(googleTemplate);
        googleFilter.setTokenServices(tokenServices);
        filters.add(googleFilter);
 
        OAuth2ClientAuthenticationProcessingFilter vkFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/vk");
        OAuth2RestTemplate vkTemplate = new OAuth2RestTemplate(vk(), oauth2ClientContext);
        vkFilter.setRestTemplate(vkTemplate);
        tokenServices = new UserInfoTokenServices(vkResource().getUserInfoUri(), vk().getClientId());
        tokenServices.setRestTemplate(vkTemplate);
        vkFilter.setTokenServices(tokenServices);
        filters.add(vkFilter);
 
        filter.setFilters(filters);
        return filter;
 
    }
}
 
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
@RestController
public class ClientController {
 
    @RequestMapping(value = { "/user", "/me"}, method = RequestMethod.GET)
    public Map<String, String> user(Principal principal) {
        Map<String, Object> details = (Map<String, Object>) ((OAuth2Authentication) principal).getUserAuthentication().getDetails();
        Map<String, String> map = new LinkedHashMap<>();
        map.put("name", (String) details.get("name"));
        map.put("email", (String) details.get("email"));
        return map;
    }
}
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
facebook:
  client:
    id: facebook
    clientId: xxx
    clientSecret: xxx
    accessTokenUri: [url]https://graph.facebook.com/oauth/access_token[/url]
    userAuthorizationUri: [url]https://www.facebook.com/dialog/oauth[/url]
    tokenName: oauth_token
    authenticationScheme: query
    clientAuthenticationScheme: form
    scope: email
  resource:
    userInfoUri: [url]https://graph.facebook.com/me[/url]
vk:
  client:
    id: vk
    clientId: xxx
    clientSecret: xxx
    accessTokenUri: [url]https://oauth.vk.com/access_token[/url]
    userAuthorizationUri: [url]https://oauth.vk.com/authorize[/url]
    tokenName: code
    authenticationScheme: query
    clientAuthenticationScheme: form
    scope: email
  resource:
    userInfoUri: [url]https://api.vk.com/method/users.get[/url]
google:
  client:
    id: google
    clientId: xxx
    clientSecret: xxx
    accessTokenUri: [url]https://accounts.google.com/o/oauth2/token[/url]
    userAuthorizationUri: [url]https://accounts.google.com/o/oauth2/auth[/url]
    clientAuthenticationScheme: form
    scope: profile email
  resource:
    userInfoUri: [url]https://www.googleapis.com/userinfo/v2/me[/url]
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.01.2017, 16:56
Ответы с готовыми решениями:

Авторизация spring oauth2
Добрый вечер. Начинаю разбираться со spring security, rest и и так далее Есть стандартная...

Google OAuth2 и spring rest
Всем привет, понадобилось мне сделать приложенице: рест сервис с аутентификацией + клиент на...

Jetty embedded + Spring MVC + Spring Security
Добрый день. По роду работы приходилось писать на JavaSE, в том числе и сложные клиент/серверные...

Spring + Basic Authentication -- Retrofit 2
Всем доброго... Воюю с настройка авторизации Spring + Basic Authentication на сервере и Retrofit...

8
Эксперт Java
2364 / 2194 / 559
Регистрация: 28.12.2010
Сообщений: 8,588
20.01.2017, 20:20 2
Fene4ka_, смотрите в дебаг на ClientController что там приходит. Возможно VK шлет свои данные с другими ключами.

Так же вводит в заблуждение что у вас вообще есть маппинг на /me ... вобщем смотрите в дебаге на тот класс, который ходит на https://api.vk.com/method/users.get и ищите что там куда кладут.
1
102 / 102 / 40
Регистрация: 24.01.2014
Сообщений: 1,244
21.01.2017, 11:09  [ТС] 3
KEKCoGEN, access token мне доходит успешно, есть подозрение, что для вк нужен users.get с параметрами, но я не точно уверен. На сам ClientController доходят details с единственным элементом в коллекции... в случае с google этих элементов 9 ...
0
Эксперт Java
2364 / 2194 / 559
Регистрация: 28.12.2010
Сообщений: 8,588
21.01.2017, 13:50 4
Цитата Сообщение от Fene4ka_ Посмотреть сообщение
access token мне доходит успешно
вам нуже не аксес токен, а /me url... Попробуйте сделать запрос на /me сами с какого нибудь rest clientа браузера и посмотрите что приходит.
1
102 / 102 / 40
Регистрация: 24.01.2014
Сообщений: 1,244
21.01.2017, 14:19  [ТС] 5
Цитата Сообщение от KEKCoGEN Посмотреть сообщение
вам нуже не аксес токен, а /me url... Попробуйте сделать запрос на /me сами с какого нибудь rest clientа браузера и посмотрите что приходит.
я же писал выше, что если сделать запрос на /user или /me, то в случае с google мне приходит Principal, который содержит все необходимые details. В случае с vk этого не происходит, собственно, для того, чтобы работало с vk нужно отредактировать ссылку на получение инфы - https://api.vk.com/method/users.get. Должно быть https://api.vk.com/method/users.get?uids=[Тут id пользователя, который необходимо достать из access token] в таком случае инфа вся приходит как надо.
так вот
Java
1
2
3
4
5
6
7
OAuth2ClientAuthenticationProcessingFilter vkFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/vk");
        OAuth2RestTemplate vkTemplate = new OAuth2RestTemplate(vk(), oauth2ClientContext);
        vkFilter.setRestTemplate(vkTemplate);
        tokenServices = new UserInfoTokenServices(vkResource().getUserInfoUri(), vk().getClientId());
        tokenServices.setRestTemplate(vkTemplate);
        vkFilter.setTokenServices(tokenServices);
        filters.add(vkFilter);
достаточно здесь сформировать правильный UserInfoUri и будет все работать, но как доставать uids из accessToken на этом этапе ?
0
Эксперт Java
2364 / 2194 / 559
Регистрация: 28.12.2010
Сообщений: 8,588
21.01.2017, 15:45 6
Fene4ka_, по обрывкам кода сложно сказать что у вас там происходит.
Насколько я понял у вас проблема в имплементации запроса на /me url (в случае vk users.get).
Если не брать во внимание всякие штуки которые делает спринг, то это простой GET запрос на url с хедером Authorization: Bearer <token>.
То есть вам надо найти тот класс в спринге который отвечает за этот реквест и дать ему кастомную имплементацию в случае с VK
1
102 / 102 / 40
Регистрация: 24.01.2014
Сообщений: 1,244
21.01.2017, 16:12  [ТС] 7
KEKCoGEN, вероятно вы правы, ток я так еще делать не умею (
0
Эксперт Java
2364 / 2194 / 559
Регистрация: 28.12.2010
Сообщений: 8,588
21.01.2017, 16:43 8
Fene4ka_, самое время научиться)
0
102 / 102 / 40
Регистрация: 24.01.2014
Сообщений: 1,244
21.01.2017, 17:02  [ТС] 9
KEKCoGEN, кажется я все понял, что мне нужно сделать, вскоре реализую и скину сюда, хочу, чтобы вы посмотрели на результат работы)

Добавлено через 11 минут
получилось как-то так, правда это немного кривова-то, наверное)
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
public class UserInfoTokenServicesForVk implements ResourceServerTokenServices {
 
 
    protected final Log logger = LogFactory.getLog(getClass());
 
    private String userInfoEndpointUrl;
 
    private final String clientId;
 
    private OAuth2RestOperations restTemplate;
 
    private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;
 
    private AuthoritiesExtractor authoritiesExtractor = new FixedAuthoritiesExtractor();
 
    private PrincipalExtractor principalExtractor = new FixedPrincipalExtractor();
 
    public UserInfoTokenServicesForVk(String userInfoEndpointUrl, String clientId) {
        this.userInfoEndpointUrl = userInfoEndpointUrl;
        this.clientId = clientId;
    }
 
    public String getUserInfoEndpointUrl() {
        return userInfoEndpointUrl;
    }
 
    public void setUserInfoEndpointUrl(String userInfoEndpointUrl) {
        this.userInfoEndpointUrl = userInfoEndpointUrl;
    }
 
    public void setTokenType(String tokenType) {
        this.tokenType = tokenType;
    }
 
    public void setRestTemplate(OAuth2RestOperations restTemplate) {
        this.restTemplate = restTemplate;
    }
 
    public void setAuthoritiesExtractor(AuthoritiesExtractor authoritiesExtractor) {
        Assert.notNull(authoritiesExtractor, "AuthoritiesExtractor must not be null");
        this.authoritiesExtractor = authoritiesExtractor;
    }
 
    public void setPrincipalExtractor(PrincipalExtractor principalExtractor) {
        Assert.notNull(principalExtractor, "PrincipalExtractor must not be null");
        this.principalExtractor = principalExtractor;
    }
 
    @Override
    public OAuth2Authentication loadAuthentication(String accessToken)
            throws AuthenticationException, InvalidTokenException {
        Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);
        if (map.containsKey("error")) {
            this.logger.debug("userinfo returned error: " + map.get("error"));
            throw new InvalidTokenException(accessToken);
        }
        return extractAuthentication(map);
    }
 
    private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
        Object principal = getPrincipal(map);
        List<GrantedAuthority> authorities = this.authoritiesExtractor
                .extractAuthorities(map);
        OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null,
                null, null, null, null);
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                principal, "N/A", authorities);
        token.setDetails(map);
        return new OAuth2Authentication(request, token);
    }
 
    /**
     * Return the principal that should be used for the token. The default implementation
     * delegates to the {@link PrincipalExtractor}.
     * @param map the source map
     * @return the principal or {@literal "unknown"}
     */
    protected Object getPrincipal(Map<String, Object> map) {
        Object principal = this.principalExtractor.extractPrincipal(map);
        return (principal == null ? "unknown" : principal);
    }
 
    @Override
    public OAuth2AccessToken readAccessToken(String accessToken) {
        throw new UnsupportedOperationException("Not supported: read access token");
    }
 
    @SuppressWarnings({ "unchecked" })
    private Map<String, Object> getMap(String path, String accessToken) {
        this.logger.info("Getting user info from: " + path);
        try {
            OAuth2RestOperations restTemplate = this.restTemplate;
            if (restTemplate == null) {
                BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
                resource.setClientId(this.clientId);
                restTemplate = new OAuth2RestTemplate(resource);
            }
            OAuth2AccessToken existingToken = restTemplate.getOAuth2ClientContext()
                    .getAccessToken();
            if (existingToken == null || !accessToken.equals(existingToken.getValue())) {
                DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(
                        accessToken);
                token.setTokenType(this.tokenType);
                restTemplate.getOAuth2ClientContext().setAccessToken(token);
            }
            return restTemplate.getForEntity(path, Map.class).getBody();
        }
        catch (Exception ex) {
            this.logger.info("Could not fetch user details: " + ex.getClass() + ", "
                    + ex.getMessage());
            return Collections.<String, Object>singletonMap("error",
                    "Could not fetch user details");
        }
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class VkCustomFilter extends AbstractAuthenticationProcessingFilter {
 
    public OAuth2RestOperations restTemplate;
    private UserInfoTokenServicesForVk tokenServices;
 
    public VkCustomFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }
 
    public void setTokenServices(UserInfoTokenServicesForVk tokenServices) {
        this.tokenServices = tokenServices;
    }
 
    public void setRestTemplate(OAuth2RestOperations restTemplate) {
        this.restTemplate = restTemplate;
    }
 
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        OAuth2AccessToken accessToken;
        try {
            accessToken = restTemplate.getAccessToken();
//            if (accessToken != null){
//                Authentication auth = SecurityContextHolder.getContext().getAuthentication();
//                Map<String, Object> details = (Map<String, Object>) auth.getDetails();
//                details.put("email", accessToken.getAdditionalInformation().get("email"));
//            }
        } catch (OAuth2Exception e) {
            BadCredentialsException bad = new BadCredentialsException("Could not obtain access token", e);
            publish(new OAuth2AuthenticationFailureEvent(bad));
            throw bad;
        }
        try {
            String userInfoEndpointUrl = tokenServices.getUserInfoEndpointUrl() + "?uids=" + accessToken.getAdditionalInformation().get("user_id").toString();
            tokenServices.setUserInfoEndpointUrl(userInfoEndpointUrl);
            OAuth2Authentication result = tokenServices.loadAuthentication(accessToken.getValue());
            if (authenticationDetailsSource!=null) {
                request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, accessToken.getValue());
                request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, accessToken.getTokenType());
                result.setDetails(authenticationDetailsSource.buildDetails(request));
            }
            publish(new AuthenticationSuccessEvent(result));
            return result;
        }
        catch (InvalidTokenException e) {
            BadCredentialsException bad = new BadCredentialsException("Could not obtain user details from token", e);
            publish(new OAuth2AuthenticationFailureEvent(bad));
            throw bad;
        }
    }
 
    private void publish(ApplicationEvent event) {
        if (eventPublisher!=null) {
            eventPublisher.publishEvent(event);
        }
    }
}
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.01.2017, 17:02

Помощь в написании контрольных, курсовых и дипломных работ здесь.

JWT Authentication using Spring Boot
Всем привет. Имеется spring boot приложение c jwt авторизацией/аутентификацией (spring secuity)....

Spring. Тесты и Spring-security
Вопрос из области почему так. Есть у меня такой вот тест: @ContextConfiguration(locations =...

Spring security c 3 на 4
Не знаю почему, но после того, как перешел на spring security 4 возникает проблема. Захожу на...

Spring security
Пытаюсь сделать spring MVC + spring security. При запуске пишет Type Exception Report Message No...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.