我有两个不同的Spring Boot应用程序,它们在不同端口(8080,8081)和不同配置(application.yml)上的localhost上运行。这些应用程序使用SSO和OAuth 2.0从授权服务器获取授权令牌。我登录到我的第一个应用程序,获得授权,一切都很好。现在,我需要与第二个Spring Boot App(在端口8081上)共享这些身份验证详细信息,以授权Authorization Server中的第二个应用程序。用Google搜索并找到2个方法:我可以尝试在两个应用之间共享HttpSession
(但我认为这是多余的)或HttpSessionSecurityContextRepository
为SecurityContextRepository
这似乎更方便。这里的问题是我无法设法这样做,而且我仍然不确定在2个应用之间共享安全上下文是个好主意。
我现在尝试的是:
我无法通过授权服务器在第二个应用上进行授权,因为它可能不是带有@Controller
的Spring Boot应用,而是任何其他应用没有 HTML表单,所以我需要要在第一个应用(使用UI)上进行授权,获取执行授权请求所需的所有数据并将其传递给第二个应用(第三个,第四个......),以便他们能够进行授权请求。
提前致谢!
答案 0 :(得分:0)
我假设您的授权/资源服务器是外部应用程序。您可以使用您的第一个应用程序成功登录,以便流程正常工作。您有两个客户端应用程序具有自己的client_id,client_secret等参数。如果这些参数不同那么授权/资源服务器将为第一个和第二个客户端应用程序返回不同的更多令牌和 sessionid cookie 。否则,您需要在授权/资源服务器中对它们进行授权。 当用户登录第一个应用程序然后在后台登录时,我会提供第二个应用程序登录。 对于自动授权第二个应用程序,您可以尝试在第一次应用程序登录成功后,使用自己的参数手动执行oauth2登录流程,并将cookie发送到您从oauth2登录获得的前端。
对于手动oauth2登录,您可以尝试以下代码:
private Cookie oauth2Login(String username, String password, String clientId, String clientSecret) {
try {
String oauthHost = InetAddress.getByName(OAUTH_HOST).getHostAddress();
HttpHeaders headers = new HttpHeaders();
RestTemplate restTemplate = new RestTemplate();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
// Basic Auth
String plainCreds = clientId + ":" + clientSecret;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = org.apache.commons.net.util.Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
headers.add("Authorization", "Basic " + base64Creds);
// form param
map.add("username", username);
map.add("password", password);
map.add("grant_type", GRANT_TYPE);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map,
headers);
// CALLING TOKEN URL
OauthTokenRespone res = null;
try {
res = restTemplate.postForObject(OAUTH_HOST, request,
OauthTokenRespone.class);
} catch (Exception ex) {
ex.printStackTrace();
}
Optional<OauthTokenRespone> optRes = Optional.ofNullable(res);
String accessToken = optRes.orElseGet(() -> new OauthTokenRespone("", "", "", "", "", ""))
.getAccess_token();
// CALLING RESOURCE
headers.clear();
map.clear();
headers.setContentType(MediaType.APPLICATION_JSON);
map.add("access_token", accessToken);
request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
Cookie oauthCookie = null;
if (accessToken.length() > 0) {
HttpEntity<String> response = restTemplate.exchange(
OAUTH_RESOURCE_URL.replace(OAUTH_HOST, oauthHost) + "?access_token=" + accessToken,
HttpMethod.POST, request, String.class);
String cookie = Optional.ofNullable(response.getHeaders().get("Set-Cookie"))
.orElseGet(() -> Arrays.asList(new String(""))).get(0);
if (cookie.length() > 0) {
String[] c = cookie.split(";")[0].split("=");
oauthCookie = new Cookie(c[0], c[1]);
oauthCookie.setHttpOnly(true);
}
}
return Optional.ofNullable(oauthCookie).orElseGet(() -> new Cookie("Ops", ""));
} catch (Throwable t) {
return new Cookie("Ops", "");
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public class OauthTokenRespone {
private String access_token;
private String token_type;
private String refresh_token;
private String expires_in;
private String scope;
private String organization;
// getter and setter
}
在第一次应用登录后调用此方法,如下所示:
Cookie oauthCookie = oauth2Login(authenticationRequest.getUsername(), authenticationRequest.getPassword(),
CLIENT_ID, CLIENT_SECRET);
获取cookie后,您需要更改其名称(例如JSESSIONID-SECOND),因为相同的cookie会相互覆盖,还需要将其域路径更改为第二个应用程序域。
response.addCookie(oauthCookie);
最后你需要为响应添加cookie(它是HttpServletResponse
引用)。
希望它有所帮助!