7

Tôi đã thiết lập một dự án nhỏ để triển khai Đăng nhập OAuth2 bằng Google+ API, sử dụng Spring Boot (1.5.2), Spring Security và Spring Security OAuth2.Spring Boot + Spring Security + Spring OAuth2 + Google Đăng nhập

Bạn có thể tìm nguồn trong: https://github.com/ccoloradoc/OAuth2Sample

tôi có thể xác thực với google và kéo ra thông tin người dùng. Tuy nhiên, sau khi đăng xuất, tôi không thể đăng nhập lại vì tôi đã nhận được "Yêu cầu không hợp lệ 400", sau khi tôi cố gắng kết nối "https://accounts.google.com/o/oauth2/auth" với RestTemplate của tôi để gọi api của google.

Xem phương pháp Thử phương pháp xác thực để tham khảo thêm.

Đây là lớp cấu hình an ninh của tôi

@Configuration 
@EnableGlobalAuthentication 
@EnableOAuth2Client 
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) 
@PropertySource(value = {"classpath:oauth.properties"}) 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 


    @Autowired 
    private UserDetailsService userDetailsService; 

    @Resource 
    @Qualifier("accessTokenRequest") 
    private AccessTokenRequest accessTokenRequest; 

    @Autowired 
    private OAuth2ClientContextFilter oAuth2ClientContextFilter; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     // @formatter:off 
     http. 
       authorizeRequests() 
       .antMatchers(HttpMethod.GET, "/login","/public/**", "/resources/**","/resources/public/**").permitAll() 
       .antMatchers("/google_oauth2_login").anonymous() 
       .anyRequest().authenticated() 
       .and() 
       .formLogin() 
       .loginPage("/login") 
       .loginProcessingUrl("/login") 
       .defaultSuccessUrl("/") 
       .and() 
       .csrf().disable() 
       .logout() 
       .logoutSuccessUrl("/") 
       .logoutUrl("/logout") 
       .deleteCookies("remember-me") 
       .and() 
       .rememberMe() 
       .and() 
       .addFilterAfter(oAuth2ClientContextFilter,ExceptionTranslationFilter.class) 
       .addFilterAfter(googleOAuth2Filter(),OAuth2ClientContextFilter.class) 
       .userDetailsService(userDetailsService); 
     // @formatter:on 
    } 

    @Bean 
    @ConfigurationProperties("google.client") 
    public OAuth2ProtectedResourceDetails auth2ProtectedResourceDetails() { 
     return new AuthorizationCodeResourceDetails(); 
    } 

    @Bean 
    public OAuth2RestTemplate oauth2RestTemplate() { 
     return new OAuth2RestTemplate(auth2ProtectedResourceDetails(), 
       new DefaultOAuth2ClientContext(accessTokenRequest)); 
    } 


    @Bean 
    public GoogleOAuth2Filter googleOAuth2Filter() { 
     return new GoogleOAuth2Filter("/google_oauth2_login"); 
    } 

    /* 
    * Building our custom Google Provider 
    * */ 
    @Bean 
    public GoogleOauth2AuthProvider googleOauth2AuthProvider() { 
     return new GoogleOauth2AuthProvider(); 
    } 

    /* 
    * Using autowired to assign it to the auth manager 
    * */ 
    @Autowired 
    public void configureGlobal(AuthenticationManagerBuilder auth) { 
     auth.authenticationProvider(googleOauth2AuthProvider()); 
    } 

    @Bean 
    public SpringSecurityDialect springSecurityDialect() { 
     return new SpringSecurityDialect(); 
    } 

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

} 

Đây là nhà cung cấp chứng thực của tôi:

public class GoogleOauth2AuthProvider implements AuthenticationProvider { 

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

    @Autowired(required = true) 
    private UserDetailsService userDetailsService; 

    @Override 
    public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
     logger.info("Provider Manager Executed"); 
     CustomOAuth2AuthenticationToken token = (CustomOAuth2AuthenticationToken) authentication; 
     UserDetailsImpl registeredUser = (UserDetailsImpl) token.getPrincipal(); 
     try { 
      registeredUser = (UserDetailsImpl) userDetailsService 
        .loadUserByUsername(registeredUser.getEmail()); 
     } catch (UsernameNotFoundException usernameNotFoundException) { 
      logger.info("User trying google/login not already a registered user. Register Him !!"); 
     } 
     return token; 
    } 

    @Override 
    public boolean supports(Class<?> authentication) { 
     return CustomOAuth2AuthenticationToken.class 
       .isAssignableFrom(authentication); 
    } 
} 

UserDetailService là một thực hiện từ lõi an ninh mùa xuân mà đọc sử dụng từ cơ sở dữ liệu và dịch nó vào một POJO UserDetails triển khai UserDetails lõi bảo mật của Spring.

Đây là thực hiện bộ lọc của tôi:

public class GoogleOAuth2Filter extends AbstractAuthenticationProcessingFilter { 

    /** 
    * Logger 
    */ 
    private static final Logger log = LoggerFactory.getLogger(GoogleOAuth2Filter.class); 

    private static final Authentication dummyAuthentication; 

    static { 
     dummyAuthentication = new UsernamePasswordAuthenticationToken(
       "dummyUserName23452346789", "dummyPassword54245", 
       CustomUserDetails.DEFAULT_ROLES); 
    } 

    private static final String NAME = "name"; 
    private static final String EMAIL = "email"; 
    private static final String PICTURE = "picture"; 

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


    @Value(value = "${google.authorization.url}") 
    private String googleAuhorizationUrl; 

    public GoogleOAuth2Filter(String defaultFilterProcessesUrl) { 
     super(defaultFilterProcessesUrl); 
    } 

    @Autowired 
    private UserService userService; 

    @Autowired 
    private OAuth2RestTemplate oauth2RestTemplate; 

    @Autowired 
    @Override 
    public void setAuthenticationManager(AuthenticationManager authenticationManager) { 
     super.setAuthenticationManager(authenticationManager); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, 
               HttpServletResponse response) throws AuthenticationException, 
      IOException, ServletException { 
     logger.info("Google Oauth Filter Triggered!!"); 
     URI authURI; 
     try { 
      authURI = new URI(googleAuhorizationUrl); 
     } catch (URISyntaxException e) { 
      log.error("\n\n\n\nERROR WHILE CREATING GOOGLE AUTH URL", e); 
      return null; 
     } 
     SecurityContext context = SecurityContextHolder.getContext(); 
     // auth null or not authenticated. 
     String code = request.getParameter("code"); 
     Map<String, String[]> parameterMap = request.getParameterMap(); 
     logger.debug(parameterMap.toString()); 
     if (StringUtils.isEmpty(code)) { 
      // Google authentication in progress. will return null. 
      logger.debug("Will set dummy user in context "); 
      context.setAuthentication(dummyAuthentication); 
      // trigger google oauth2. 
      // ERROR ON SECOND LOGIN ATTEMPT 
      oauth2RestTemplate.postForEntity(authURI, null, Object.class); 
      return null; 
     } else { 
      logger.debug("Response from Google Recieved !!"); 

      ResponseEntity<Object> forEntity = oauth2RestTemplate.getForEntity(
        "https://www.googleapis.com/plus/v1/people/me/openIdConnect", 
        Object.class); 

      @SuppressWarnings("unchecked") 
      Map<String, String> profile = (Map<String, String>) forEntity.getBody(); 

      CustomOAuth2AuthenticationToken authenticationToken = getOAuth2Token(
        profile.get(EMAIL), profile.get(NAME), profile.get(PICTURE)); 
      authenticationToken.setAuthenticated(false); 

      return getAuthenticationManager().authenticate(authenticationToken); 
     } 
    } 

    private CustomOAuth2AuthenticationToken getOAuth2Token(
      String email, String name, String picture) { 

     User user = userService.findByEmail(email); 
     //Register user 
     if(user == null) { 
      user = new User(name, email, picture); 
      userService.saveOrUpdate(user); 
     } 

     UserDetailsImpl registeredUser = new UserDetailsImpl(name, email, picture); 

     CustomOAuth2AuthenticationToken authenticationToken = 
       new CustomOAuth2AuthenticationToken(registeredUser); 

     return authenticationToken; 
    } 

} 

Trả lời

3

Mọi thứ trở nên dễ dàng hơn nhiều nếu bạn sử dụng phương pháp EnableOAuth2Sso (mặc dù nó ẩn rất nhiều quá trình từ bạn). The Spring Boot tutorial on OAuth2 là khá kỹ lưỡng cho điều này, và có những ví dụ khác trực tuyến mà tôi nôi từ (ví dụ https://github.com/SoatGroup/spring-boot-google-auth/http://dreamix.eu/blog/java/configuring-google-as-oauth2-authorization-provider-in-spring-boot) đã giúp một chút. Cuối cùng, this was the resource đã giúp tôi nhiều nhất - bao gồm toàn bộ quá trình và tích hợp các ứng dụng phía máy khách.

Nếu bạn muốn thực hiện việc này ở cấp độ thấp hơn, có rất nhiều chi tiết về toàn bộ quy trình và cách hoạt động trong Spring trên Pivotal blog post.

Các vấn đề liên quan