我使用Spring Security OAuth 2.0和JWT为我的身份验证服务器实现了密码授予 . 我通过扩展AuthorizationServerConfigurerAdapter来创建服务器 . 我能够给服务器一个用户名/密码并获得一个JWT令牌 . 我使用ResourceConfiguration扩展其他服务上的ResourceServerConfigurerAdapter类,以便在进行Web服务调用时验证JWT . 贴在下面是我的代码 .

我想让我的Native Mobile应用程序能够使用Facebook,Gmail,Linked等登录...我想按照所附文章中的步骤操作:

https://ole.michelsen.dk/blog/social-signin-spa-jwt-server.html

  • 用户在移动端进行OAuth跳舞,并向我发送他们正在使用的社交服务的访问令牌 .

  • 我收到了访问令牌,并使用它来呼叫相应的社交服务 .

  • 如果令牌有效,则用户无法登录,则会引发错误 .

  • 如果令牌有效,我从社交服务获取用户详细信息并使用它在我的数据存储中创建"Social User",该数据存储将绑定到现有或新的系统用户 .

  • 使用社交用户创建系统用户后,或者社交用户与现有系统用户绑定后,JWT令牌将被发送回移动应用程序 .

  • 此JWT令牌应类似于Spring Security OAuth 2.0密码授予流创建的JWT令牌,并且在授权用户时应由我的ResourceServerConfiguration接受 .

我在网上搜索了符合我标准的解决方案,但我找不到任何解决方案 . 我的要求合理吗?是否有更简单的方法,允许用户通过用户名/密码和社交媒体身份验证登录,同时获取JWT令牌 . 我发现的一个例子使用OAuth2ClientAuthenticationProcessingFilter来执行上面提到的逻辑,但我不知道OAuth2ClientAuthenticationProcessingFilter是如何工作的,并且找不到任何文档 . 如果某人必须使用类似的技术堆栈实现类似的要求,请告诉我您用于实施此解决方案的技术 .

在身份验证服务器上:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;

    @Value("${clientId}")
    private String clientId;

    @Value("${clientSecret}")
    private String clientSecret;

    @Value("${jwtSigningKey}")
    private String jwtSigningKey;

    @Value("${accessTokenValiditySeconds}")
    private String accessTokenValiditySeconds;

    @Value("${refreshTokenValiditySeconds}")
    private String refreshTokenValiditySeconds;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter(){
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
        accessTokenConverter.setSigningKey(jwtSigningKey);
        return accessTokenConverter;
    }

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

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

    // Added for refresh token capability
    @Bean
    @Primary
    public DefaultTokenServices tokenServices(){
        final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

    @Override
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient(clientId)
                    .secret(clientSecret)
                    .authorizedGrantTypes("password", "refresh_token")
                    .scopes("read","write")
                    .accessTokenValiditySeconds(Integer.valueOf(accessTokenValiditySeconds)) // 1 hour
                    .refreshTokenValiditySeconds(Integer.valueOf(refreshTokenValiditySeconds));// 30 days
    }

    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {

        // Add the JWT token enhancer to the token enhancer chain then add to endpoints
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));

        endpoints.tokenStore(tokenStore())
                .tokenEnhancer(tokenEnhancerChain)
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST)
                .accessTokenConverter(accessTokenConverter());
    }

    @Override
    public void configure(final AuthorizationServerSecurityConfigurer securityConfigurer) throws Exception {
        securityConfigurer.checkTokenAccess("permitAll()");
        super.configure(securityConfigurer);
    }
}

public class JWTTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(final OAuth2AccessToken accessToken,
                                     final OAuth2Authentication authentication) {

        Map<String, Object> additionalInfo = new HashMap<>();

        // Get the user detail implementation
        UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();

        // add userId and roles to the JWT token
        additionalInfo.put("user_id", userDetails.getUserId());
        additionalInfo.put("email", userDetails.getEmail());
        additionalInfo.put("user_name", userDetails.getUsername());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);

        return accessToken;
    }
}

在每个微服务上:

@Configuration
@EnableResourceServer
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@ComponentScan("com.test.security")
@Profile({"prod", "qa", "dev"})
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

  @Value("${jwtSigningKey}")
  private String jwtSigningKey;

  // http security concerns
  @Override
  public void configure(final HttpSecurity http) throws Exception {

    http.authorizeRequests()
        .antMatchers("/swagger-ui.html").permitAll()
        .antMatchers("/hystrix/**").permitAll()
        .antMatchers("/admin/hystrix.stream/**").permitAll()
        .antMatchers("/admin/health/**").permitAll()
        .antMatchers("/admin/info/**").permitAll()
        .antMatchers("/admin/**").authenticated()
        .antMatchers("/greetings/**").authenticated()
        .and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and().csrf().disable();
  }

  @Override
  public void configure(final ResourceServerSecurityConfigurer config) {
    config.tokenServices(tokenServices());
  }

  @Bean
  public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
    accessTokenConverter.setSigningKey(jwtSigningKey);
    return accessTokenConverter;
  }

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

  // Added for refresh token capability
  @Bean
  @Primary
  public DefaultTokenServices tokenServices() {
    final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore());
    defaultTokenServices.setSupportRefreshToken(true);
    return defaultTokenServices;
  }
}