it would be best if there is a document or example that is available to the public to show how to integrate Angular http(with credentials) with Spring Security.
I have a way to login which I will show the code below, but I think there must be a better way. Maybe with the option in the Http header withCredentials, but where you provide your credentials?
It is keeping idToken from external auth. service (Google+) and type ( determine type of the auth. service) in headers, so you dont need pass them as a request parameter or as a path variable.
Then in the backend (Spring Java), there is a spring AOP that save the user to the SecurityContext after verification.
Angular Http Call
import { Http, Headers, RequestOptions } from '@angular/http';
...
constructor(private http: Http...){...}
...
search(){
let options ;
if (this.loginService.user) {
let headers = new Headers({ 'idToken': this.loginService.user.idToken,'type':this.loginService.user.type});
options = new RequestOptions({ headers: headers });
}
return this.http
.get("searchurl",options)
...
GooglePlusAuthService
import java.util.Collections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
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.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
@Service
public class GooglePlusAuthService implements AuthenticationService{
private Logger logger = LoggerFactory.getLogger(GooglePlusAuthService.class);
private static String clientId;
@Value("${client_id.google}")
public void setClientId(String clientId){
GooglePlusAuthService.clientId=clientId;
}
@Override
public void login(String token) {
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new JacksonFactory())//.setIssuer(clientId)
.setAudience(Collections.singletonList(clientId))
.build();
GoogleIdToken idToken;
try {
idToken = verifier.verify(token);
if (idToken != null) {
Payload payload = idToken.getPayload();
User user = new User();
user.setId(Authenticator.AUTH_TYPE_GOOGLE+"_"+payload.getSubject());
user.setUsername((String) payload.get("name"));
user.setToken(token);
AuthenticationUtils.setUser(user);
} else {
logger.info("Failed to login with Google plus. Invalid ID token.");
}
} catch (Exception e) {
e.printStackTrace();
logger.error("Failed to login with Google plus." + e.getMessage());
}
}
}
AuthenticationUtils
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
public class AuthenticationUtils {
public static void setUser(User user){
Authentication authentication = new UsernamePasswordAuthenticationToken(user, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
public static User getUser(){
if(SecurityContextHolder.getContext().getAuthentication()!=null)
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return null;
}
}
This code has a bug which I am also trying to find out.
Why AuthenticationUtils.getUser()
is giving me the last signed in user when I didn't provide any credential info. I just opened the url with a private browser and it gets me the last signed in user in the backend.