OAuth2 Аутентификация с использованием социальной учетной записи и сохранение токена jwt в базе данных. - PullRequest
0 голосов
/ 19 мая 2019

Я слежу за серией учебников: https://www.callicoder.com/spring-boot-security-oauth2-social-login-part-1/ это самый лучший учебник, но токен не сохраняется в базе данных, и формат токена мне не подходит.

Мне нужны access_token и refresh_token, например:

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21pemVkIjoidHJ1ZSIsInVzZXJfbmFtZSI6ImRqb25pa2dhQGdtYWlsLmNvbSIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJuYW1lIjoi0JXQstCz0LXQvdC40Lkg0JTQstC-0YDRhtC10LLQvtC5IiwiaWQiOjksImV4cCI6MTU1ODI1NTU1MCwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6Ijg1NjMxZmQ3LTRmNDMtNDIzNC05M2RlLTI5NTUxNDJjZmEzZiIsImNsaWVudF9pZCI6Imp3dENsaWVudElkUGFzc3dvcmQifQ.yP4dWiSdWPh1wsrirXzG6p19gjx5yI9MvsIjyESe1is",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21pemVkIjoidHJ1ZSIsInVzZXJfbmFtZSI6ImRqb25pa2dhQGdtYWlsLmNvbSIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdGkiOiI4NTYzMWZkNy00ZjQzLTQyMzQtOTNkZS0yOTU1MTQyY2ZhM2YiLCJuYW1lIjoi0JXQstCz0LXQvdC40Lkg0JTQstC-0YDRhtC10LLQvtC5IiwiaWQiOjksImV4cCI6MTU2MDg0NjY1MCwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6Ijg4Y2FlNzYzLTJmOTItNDQ2Ni1hMmU3LTk0NGZmODQ4NmQ5NCIsImNsaWVudF9pZCI6Imp3dENsaWVudElkUGFzc3dvcmQifQ.0cUifDOtxAryTGD0qn2GHPtiAoNSlDfd3fpamlGGGrE",
    "expires_in": 899,
    "scope": "read write"
}

После аутентификации в социальной учетной записи, такой как Google, Facebook, я создаю токен вручную и перенаправляю, чтобы получить данные с токеном, но токен недействителен.

get - http://localhost:8080/user/me 
bearer: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzb3VyY2VJZFRlc3QiXSwiY3VzdG9taXplZCI6InRydWUiLCJ1c2VyX25hbWUiOiJkam9uaWtnYUBnbWFpbC5jb20iLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwibmFtZSI6ItCV0LLQs9C10L3QuNC5INCU0LLQvtGA0YbQtdCy0L7QuSIsImlkIjo5LCJleHAiOjE1NTgyNTM3NTEsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiJhYzY0M2M2Yy0wZDYyLTQ2MDMtOWYxMy0wODE5MmNlYmYzZDAiLCJjbGllbnRfaWQiOiJqd3RDbGllbnRJZFBhc3N3b3JkIn0.d9_1gc_9PbrkG5mwoLRymBiPWpmH0VTcSEdnhz1aaxA

Я получаю ответ

{
    "error": "access_denied",
    "error_description": "Invalid token does not contain resource id (jwtClientIdPassword)"
}

У меня есть интерфейс - React, Сервер авторизации - Spring Security 5.0, postgres. Также я аутентифицируюсь с потоком OAuth 2.0 и паролем. Токен хранится в базе данных.

Мой адаптер авторизации

@Bean
public TokenEnhancer tokenEnhancer() {
  return new CustomTokenEnhancer();
}

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

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
  tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
  endpoints.authenticationManager(this.authenticationManager)
          .tokenEnhancer(tokenEnhancerChain)
          .tokenStore(tokenStore());
}


@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
  CustomTokenConverter converter = new CustomTokenConverter();
  converter.setSigningKey(signingKey);
  return converter;
}

@Bean
@Primary
//Making this primary to avoid any accidental duplication with another token service instance of the same name
public DefaultTokenServices tokenServices() {
  DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
  defaultTokenServices.setTokenStore(tokenStore());
  defaultTokenServices.setSupportRefreshToken(true);
  defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
  return defaultTokenServices;
}

@Bean
public TokenStore tokenStore() {
  return new JwtTokenStore(jwtAccessTokenConverter());
}

Сетевой адаптер My Security

@Bean
    public HttpCookieOAuth2AuthorizationRequestRepository cookieAuthorizationRequestRepository() {
        return new HttpCookieOAuth2AuthorizationRequestRepository();
    }

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return DefaultPasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

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

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

        http
                .cors()
                    .and()
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .exceptionHandling()
                    .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                    .and()
                .authorizeRequests()
                    .antMatchers("/auth/**", "/oauth2/**").permitAll()
                    .anyRequest()
                        .authenticated()
                    .and()
                .oauth2Login()
                    .authorizationEndpoint().baseUri("/oauth2/authorize")
                        .authorizationRequestRepository(cookieAuthorizationRequestRepository())
                        .and()
                    .redirectionEndpoint().baseUri("/oauth2/callback/*")
                        .and()
                    .userInfoEndpoint()
                        .userService(customOAuth2UserService)
                        .and()
                    .successHandler(oAuth2AuthenticationSuccessHandler)
                    .failureHandler(oAuth2AuthenticationFailureHandler);

        http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

В oAuth2AuthenticationSuccessHandler.onAuthenticationSuccess я пытаюсь создать токен

@Component
public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private TokenProvider tokenProvider;

    private AppProperties appProperties;

    private HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository;

 =====   

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        String targetUrl = determineTargetUrl(request, response, authentication);

        if (response.isCommitted()) {
            logger.debug("Response has already been committed. Unable to redirect to " + targetUrl);
            return;
        }

        clearAuthenticationAttributes(request, response);
        getRedirectStrategy().sendRedirect(request, response, targetUrl);
    }

    protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        Optional<String> redirectUri = CookieUtils.getCookie(request, REDIRECT_URI_PARAM_COOKIE_NAME)
                .map(Cookie::getValue);

        if(redirectUri.isPresent() && !isAuthorizedRedirectUri(redirectUri.get())) {
            throw new BadRequestException("Sorry! We've got an Unauthorized Redirect URI and can't proceed with the authentication");
        }

        String targetUrl = redirectUri.orElse(getDefaultTargetUrl());

        OAuth2AccessToken accessToken = tokenProvider.createAccessToken(authentication);

        return UriComponentsBuilder.fromUriString(targetUrl)
                .queryParam("token", accessToken.getValue())
                .build().toUriString();
    }

Здесь я пытаюсь создать токен jwt

@Service
public class TokenProvider {

  private static final Logger logger = LoggerFactory.getLogger(TokenProvider.class);

  private AppProperties appProperties;

  @Autowired
  private TokenStore tokenStore;

  @Autowired
  private AuthorizationServerEndpointsConfiguration configuration;

  public TokenProvider(AppProperties appProperties) {
    this.appProperties = appProperties;
  } 

public OAuth2AccessToken createAccessToken(Authentication authentication) {

  UserPrincipal user =  (UserPrincipal)authentication.getPrincipal();
  List<String> scopes = new ArrayList<>();
  scopes.add("read");
  scopes.add("write");

  Map<String, String> requestParameters = new HashMap<String, String>();
  Map<String, Serializable> extensionProperties = new HashMap<String, Serializable>();

  requestParameters.put("client_id", "jwtClientIdPassword");
  requestParameters.put("grant_type", "password");
  requestParameters.put("scope", "read,write");
  requestParameters.put("client_secret", "client");
  requestParameters.put("username", user.getEmail());
  requestParameters.put("password", user.getPassword());

  boolean approved = true;
  Set<String> responseTypes = new HashSet<String>();
  responseTypes.add("code");

  OAuth2Request oauth2Request = new OAuth2Request(requestParameters, "jwtClientIdPassword", user.getAuthorities(), approved, new HashSet<String>(scopes), new HashSet<String>(Arrays.asList("resourceIdTest")), null, responseTypes, extensionProperties);
  UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, "N/A", user.getAuthorities());
  OAuth2Authentication auth = new OAuth2Authentication(oauth2Request, authenticationToken);
  AuthorizationServerTokenServices tokenService = configuration.getEndpointsConfigurer().getTokenServices();
  OAuth2AccessToken token = tokenService.createAccessToken(auth);

  return token;
}

Я не уверен, что делаю все правильно.

1 Ответ

0 голосов
/ 20 мая 2019

Я выяснил, в чем проблема.У меня был неправильный параметр, это

new HashSet<String>(Arrays.asList("resourceIdTest"))

, и я изменил код

public OAuth2AccessToken createAccessToken(Authentication authentication) {

    UserPrincipal userPrincipal =  (UserPrincipal)authentication.getPrincipal();
    Set<GrantedAuthority> authorities = new HashSet(userPrincipal.getAuthorities());

    Map<String, String> requestParameters = new HashMap<>();
    String clientId = "jwtClientIdPassword";
    boolean approved = true;
    Set<String> resourceIds = new HashSet<>();
    Set<String> responseTypes = new HashSet<>();
    responseTypes.add("code");
    Map<String, Serializable> extensionProperties = new HashMap<>();

    List<String> scopes = new ArrayList<>();
    scopes.add("read");
    scopes.add("write");

    OAuth2Request oAuth2Request = new OAuth2Request(requestParameters, clientId,
            authorities, approved, new HashSet<>(scopes),
            resourceIds, null, responseTypes, extensionProperties);

    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userPrincipal, null, authorities);
    OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken);
    AuthorizationServerTokenServices tokenService = configuration.getEndpointsConfigurer().getTokenServices();

    OAuth2AccessToken token = tokenService.createAccessToken(auth);
    return token;
  }
...