我有一个关于不同的端口(8080,8081)和不同CONFIGS(application.yml)本地主机运行两个不同的春季启动应用程序。 这些应用程序使用SSO使用OAuth 2.0,从授权服务器获得授权令牌。 我登录到我的第一个应用程序,获得授权和一切的伟大工程在这里。 现在我需要分享第二春启动应用程序(在端口8081),这些认证信息授权的授权服务器第二应用程序。 用Google搜索,发现2个aproaches:我可以尝试共享HttpSession
两个应用程序之间(但我认为这是多余的)或HttpSessionSecurityContextRepository
为SecurityContextRepository
这似乎更方便。 这里的问题是,我无法管理这样做,我真不知道,这是一个好主意,分享2个应用程序之间的安全上下文。
我尝试了现在:
- 从通过在GET请求(定制按为授权服务器请求规范)头第一应用程序分享授权令牌,但它没有工作-第二次的应用程序不考虑采取这种令牌。
- 分享从第一个应用程序授权cookie来第二次,但它并不能工作。
我无法通过授权服务器上做第二应用程序的授权,因为它可能不是一个春天启动应用程序与@Controller
但任何其他应用,而无需 HTML表单,所以我需要授权的第一应用(与UI),让所有的数据,需要进行授权的请求,并将它传递给第二应用(第三,第四......),所以他们能够做授权的请求了。
提前致谢!
我相信,你的授权/资源服务器是外部application.And你可以用你的第一个应用程序,以便流是working.You有自己的CLIENT_ID,client_secret两个客户端应用程序等parameters.If这些参数是不同的,那么授权/资源成功登录application.Otherwise你需要在授权/资源服务器授权他们两个服务器将返回第一和第二客户不同bareer令牌和会话ID的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);
让饼干后,您需要更改其名称(例如JSESSIONID-秒),因为同样的Cookie将覆盖对方,还需要其领域路径更改为第二个应用程序域。
response.addCookie(oauthCookie);
最后你需要添加cookie来响应(这是HttpServletResponse
参考)。
希望能帮助到你!