package org.springframework.social.connect.web;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.social.ExpiredAuthorizationException;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.ConnectionFactory;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.connect.support.OAuth1ConnectionFactory;
import org.springframework.social.connect.support.OAuth2ConnectionFactory;
import org.springframework.social.support.URIBuilder;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.servlet.view.RedirectView;
/**
*
* @author Ju
* @see ProviderSignInController
*/
public class ProviderSignInControllerEx extends ProviderSignInController {
private final static Log logger = LogFactory
.getLog(ProviderSignInControllerEx.class);
private final ConnectionFactoryLocator connectionFactoryLocator;
private final ConnectSupport webSupport = new ConnectSupport();
private final UsersConnectionRepository usersConnectionRepository;
private final SignInAdapter signInAdapter;
private String signInUrl = "/signin";
private String signUpUrl = "/signup";
private String postSignInUrl = "/";
@Inject
public ProviderSignInControllerEx(
ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository,
SignInAdapter signInAdapter) {
super(connectionFactoryLocator, usersConnectionRepository,
signInAdapter);
this.connectionFactoryLocator = connectionFactoryLocator;
this.usersConnectionRepository = usersConnectionRepository;
this.signInAdapter = signInAdapter;
this.webSupport.setUseAuthenticateUrl(true);
}
@RequestMapping(value = "/{providerId}", method = RequestMethod.POST)
public RedirectView signIn(@PathVariable String providerId,
NativeWebRequest request) {
ConnectionFactory<?> connectionFactory = connectionFactoryLocator
.getConnectionFactory(providerId);
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
Map<String, String[]> params = request.getParameterMap();
if (params != null)
for (Map.Entry<String, String[]> entry : params.entrySet()) {
if (entry.getValue() != null && entry.getValue().length > 0) {
parameters.put(entry.getKey(),
Arrays.asList(entry.getValue()));
}
}
try {
return new RedirectView(webSupport.buildOAuthUrl(connectionFactory,
request, parameters));
} catch (Exception e) {
logger.error("sigin, providerId=" + providerId, e);
return redirect(URIBuilder.fromUri(signInUrl)
.queryParam("error", "provider").build().toString());
}
}
@RequestMapping(value = "/{providerId}", method = RequestMethod.GET, params = "oauth_token")
public RedirectView oauth1Callback(@PathVariable String providerId,
NativeWebRequest request) {
try {
OAuth1ConnectionFactory<?> connectionFactory = (OAuth1ConnectionFactory<?>) connectionFactoryLocator
.getConnectionFactory(providerId);
Connection<?> connection = webSupport.completeConnection(
connectionFactory, request);
return handleSignIn(connection, request);
} catch (Exception e) {
return redirect(URIBuilder.fromUri(signInUrl)
.queryParam("error", "provider").build().toString());
}
}
@RequestMapping(value = "/{providerId}", method = RequestMethod.GET, params = "code")
public RedirectView oauth2Callback(@PathVariable String providerId,
@RequestParam("code") String code, NativeWebRequest request) {
try {
OAuth2ConnectionFactory<?> connectionFactory = (OAuth2ConnectionFactory<?>) connectionFactoryLocator
.getConnectionFactory(providerId);
Connection<?> connection = webSupport.completeConnection(connectionFactory,
request);
try {
// connection = webSupport.completeConnection(connectionFactory,
// request);
} catch (ExpiredAuthorizationException e) {
// 试图删除connection,并重试 ,TODO 话说spring-social 1.1.0后,支持refresh了
}
return handleSignIn(connection, request);
} catch (Exception e) {
logger.warn(
"Exception while handling OAuth2 callback ("
+ e.getMessage() + "). Redirecting to " + signInUrl,
e);
return redirect(URIBuilder.fromUri(signInUrl)
.queryParam("error", "provider").build().toString());
}
}
private RedirectView handleSignIn(Connection<?> connection,
NativeWebRequest request) {
List<String> userIds = usersConnectionRepository
.findUserIdsWithConnection(connection);
if (userIds.size() == 0) {
ProviderSignInAttempt signInAttempt = new ProviderSignInAttempt(
connection, connectionFactoryLocator,
usersConnectionRepository);
request.setAttribute(ProviderSignInAttempt.SESSION_ATTRIBUTE,
signInAttempt, RequestAttributes.SCOPE_SESSION);
return redirect(signUpUrl);
} else if (userIds.size() == 1) {
usersConnectionRepository
.createConnectionRepository(userIds.get(0))
.updateConnection(connection);
String originalUrl = signInAdapter.signIn(userIds.get(0),
connection, request);
return originalUrl != null ? redirect(originalUrl)
: redirect(postSignInUrl);
} else {
return redirect(URIBuilder.fromUri(signInUrl)
.queryParam("error", "multiple_users").build().toString());
}
}
private RedirectView redirect(String url) {
return new RedirectView(url, true);
}
/**
* Sets the URL of the application's sign in page. Defaults to "/signin".
*
* @param signInUrl
* the signIn URL
*/
public void setSignInUrl(String signInUrl) {
this.signInUrl = signInUrl;
}
/**
* Sets the URL to redirect the user to if no local user account can be
* mapped when signing in using a provider. Defaults to "/signup".
*
* @param signUpUrl
* the signUp URL
*/
public void setSignUpUrl(String signUpUrl) {
this.signUpUrl = signUpUrl;
}
/**
* Sets the default URL to redirect the user to after signing in using a
* provider. Defaults to "/".
*
* @param postSignInUrl
* the postSignIn URL
*/
public void setPostSignInUrl(String postSignInUrl) {
this.postSignInUrl = postSignInUrl;
}
/**
* Configures the base secure URL for the application this controller is
* being used in e.g. <code>https://myapp.com</code>. Defaults to null. If
* specified, will be used to generate OAuth callback URLs. If not
* specified, OAuth callback URLs are generated from web request info. You
* may wish to set this property if requests into your application flow
* through a proxy to your application server. In this case, the request URI
* may contain a scheme, host, and/or port value that points to an internal
* server not appropriate for an external callback URL. If you have this
* problem, you can set this property to the base external URL for your
* application and it will be used to construct the callback URL instead.
*
* @param applicationUrl
* the application URL value
*/
public void setApplicationUrl(String applicationUrl) {
webSupport.setApplicationUrl(applicationUrl);
}
}