hier ist mein nehmen auf die erforderlichen Federsicherheitskomponenten:
Filter:
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.Assert;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class GoogleIdAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final long serialVersionUID = 1L;
private String tokenParamName = "googleIdToken";
/**
* Creates an instance which will authenticate against the supplied
* {@code AuthenticationManager} and which will ignore failed authentication attempts,
* allowing the request to proceed down the filter chain.
*
* @param authenticationManager the bean to submit authentication requests to
* @param defaultFilterProcessesUrl the url to check for auth requests on (e.g. /login/google)
*/
public GoogleIdAuthenticationFilter(AuthenticationManager authenticationManager, String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String token = request.getParameter(tokenParamName);
if (token == null) {
return null;
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Google ID Token Authorization parameter found with value '" + token + "'");
}
Object details = this.authenticationDetailsSource.buildDetails(request);
GoogleIdAuthenticationToken authRequest = new GoogleIdAuthenticationToken(token, details);
Authentication authResult = getAuthenticationManager().authenticate(authRequest);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Authentication success: " + authResult);
}
return authResult;
}
public String getTokenParamName() {
return tokenParamName;
}
public void setTokenParamName(String tokenParamName) {
this.tokenParamName = tokenParamName;
}
}
Authentifizierungsanbieter:
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.apache.ApacheHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import javax.annotation.Resource;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
public class GoogleIdAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LoggerFactory.getLogger(GoogleIdAuthenticationProvider.class);
private String clientId;
@Resource
private UserDetailsService userDetailsService;
private HttpTransport httpTransport = new ApacheHttpTransport();
private JsonFactory jsonFactory = new JacksonFactory();
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("This authentication provider does not support instances of type %s", authentication.getClass().getName()));
}
return null;
}
GoogleIdAuthenticationToken googleIdAuthenticationToken = (GoogleIdAuthenticationToken) authentication;
if (logger.isDebugEnabled())
logger.debug(String.format("Validating google login with token '%s'", googleIdAuthenticationToken.getCredentials()));
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(httpTransport, jsonFactory)
.setAudience(Collections.singletonList(getClientId()))
.build();
GoogleIdToken googleIdToken = null;
try {
googleIdToken = verifier.verify((String) googleIdAuthenticationToken.getCredentials());
if (googleIdToken == null) {
throw new BadCredentialsException("Unable to verify token");
}
} catch (IOException|GeneralSecurityException e) {
throw new BadCredentialsException("Unable to verify token", e);
}
Payload payload = googleIdToken.getPayload();
// Get profile information from payload
String email = payload.getEmail();
if (logger.isDebugEnabled()) {
logger.debug(String.format("Loading user details for email '%s'", email));
}
UserDetails userDetails = null;
try {
userDetails = userDetailsService.loadUserByUsername(email);
if (!userDetails.isAccountNonLocked()) {
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked"));
}
if (!userDetails.isEnabled()) {
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"));
}
if (!userDetails.isAccountNonExpired()) {
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired"));
}
} catch (UsernameNotFoundException e) {
// provision a new user?
throw e;
}
return new GoogleIdAuthenticationToken((String) googleIdAuthenticationToken.getCredentials(), userDetails.getUsername(), userDetails.getAuthorities(), authentication.getDetails());
}
@Override
public boolean supports(Class<? extends Object> authentication) {
return (GoogleIdAuthenticationToken.class.isAssignableFrom(authentication));
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
}
token:
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.ArrayList;
import java.util.Collection;
public class GoogleIdAuthenticationToken extends AbstractAuthenticationToken {
private String credentials;
private Object principal;
public GoogleIdAuthenticationToken(String token, Object details) {
super(new ArrayList<>());
this.credentials = token;
setDetails(details);
setAuthenticated(false);
}
GoogleIdAuthenticationToken(String token, String principal, Collection<? extends GrantedAuthority> authorities, Object details) {
super(authorities);
this.credentials = token;
this.principal = principal;
setDetails(details);
setAuthenticated(true);
}
@Override
public Object getCredentials() {
return credentials;
}
@Override
public Object getPrincipal() {
return principal;
}
}
Nachdem in der Verstopfungs über Sie nur brauchen, um es zu "/ login/google" (oder was auch immer Sie konfiguriert haben) mit dem Token durch Google in der ‚googleIdToken zurück '(oder was auch immer Sie konfiguriert haben).
Sie müssen sich um einige Probleme kümmern. Wie würden Sie lokale Benutzer für Spring Sec Application und externe Benutzer von Google verwalten? Wie werden Principals von Google in den Principal von Spring Sec übersetzt? Das sind die zwei, die ich von ganzem Herzen unterscheiden kann. – lazyneuron
"Wie würden Sie lokale Benutzer für Spring Sec Application und externe Benutzer von Google verwalten?" Ich werde sie genauso verwalten, einen neuen Benutzer zu erstellen, wenn der nicht bereits existiert. "Wie werden Principals von Google in Spring Sec Principal übersetzt?" Ich muss dem Google-Benutzer eine Option zur Verfügung stellen, um den Spring sec-Benutzer zu binden, indem er eine gültige Login/Passwort-Kombination angibt (für die der Spring-Benutzer registriert wurde). –