用例: 我有两个应用程序:
1)第一个是Spring启动应用程序,我们从这里公开我们的rest端点。
我希望在从第二个应用程序调用时使用Azure AD保护我的第一个应用程序,并且我希望以静默方式执行此操作,即在服务调用服务发生时,我不应该提示输入用户名和密码。
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AADAuthenticationFilter aadAuthFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/home").permitAll();
http.authorizeRequests().antMatchers("/api/**").authenticated();
http.logout().logoutSuccessUrl("/").permitAll();
http.authorizeRequests().anyRequest().permitAll();
http.csrf().disable();
http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);
}
}
@RestController
public class MyRestController{
@RequestMapping(value = "/api/todolist", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> addNewTodoItem(@RequestBody TodoItem item) {
item.setID(todoList.size() + 1);
todoList.add(todoList.size(), item);
return new ResponseEntity<>("Entity created", HttpStatus.CREATED);
}
}
2)第二个应用程序正在调用此Rest服务。 (你能不能把它当作一个只调用我们的休息服务然后做一些处理的java客户端)。
我希望在从第二个应用程序调用时使用Azure AD保护我的第一个应用程序,并且我希望以静默方式执行此操作,即在服务调用服务发生时不应提示输入用户名和密码
下面是代码:
package sample.aad.security;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import org.json.JSONObject;
import ch.qos.logback.core.net.SyslogOutputStream;
public class MyClass {
public static void main(String[] args) throws Exception {
URL url = new URL("https://login.microsoftonline.com/{tenantId}/oauth2/token");
Map<String, Object> params = new LinkedHashMap<>();
params.put("grant_type", "client_credentials");
params.put("client_id", "b2846a59-33e9-4046-8c94-795d8087f453");
params.put("client_secret", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
params.put("resource", APPID);
StringBuilder postData = new StringBuilder();
for (Map.Entry<String, Object> param : params.entrySet()) {
if (postData.length() != 0)
postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");// multipart/form-data
conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
conn.setDoOutput(true);
conn.getOutputStream().write(postDataBytes);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String output;
String last = null;
System.out.println("Output from Server .... \n");
while ((output = in.readLine()) != null) {
System.out.println(output);
if (last == null) {
last = output;
} else {
last.concat(output);
}
}
JSONObject jsonObj = new JSONObject(last.toString());
System.out.println(jsonObj.get("access_token"));
System.out.println(jsonObj.get("token_type"));
invokeRestUrlClientStatic(jsonObj.get("token_type") + " " + jsonObj.get("access_token"));
}
public static void invokeRestUrlClientStatic(String accessToken) {
try {
System.out.println("Invoking");
System.out.println(accessToken);
// Call to Rest service from First Application
URL url = new URL(" http://localhost:8080/api/todolist/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", accessToken);
String input = "{\"qty\":100,\"name\":\"iPad 4\"}";
OutputStream os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:我在用户无法登录的任何一个应用程序中都没有任何WebUi。
但我收到以下错误:
引起:com.microsoft.aad.adal4j.AuthenticationException:{“error_description”:“AADSTS50058:已发送静默登录请求但未登录任何用户。\ r \ nTrace ID:b27a4ce6- f1ed-4a5c-b28f-6ee16f990400 \ r \ n相关ID:168e6a13-8cf6-409f-864a-9f190746edfd \ r \ n时间戳:2018-03-17 10:46:35Z“,”错误“:”invalid_grant“} 在com.microsoft.aad.adal4j.AdalTokenRequest.executeOAuthRequestAndProcessResponse(AdalTokenRequest.java:107)〜[adal4j-1.2.0.jar:1.2.0] 在com.microsoft.aad.adal4j.AuthenticationContext.acquireTokenCommon(AuthenticationContext.java:816)~ [adal4j-1.2.0.jar:1.2.0] 在com.microsoft.aad.adal4j.AuthenticationContext.access $ 100(AuthenticationContext.java:64)〜[adal4j-1.2.0.jar:1.2.0]
我错过了一些有效的东西。
我也试过下面的代码(对于我的第二个应用程序):但仍然得到相同的错误
public static void main(String [] args)抛出MalformedURLException,Exception {
String app_id_uri = "APP ID URL";
String authority = "https://login.microsoftonline.com/common/";
String clientId = "b2846a59-33e9-4046-8c94-795d8087f453";
String clientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
AuthenticationContext context = null;
AuthenticationResult result = null;
ExecutorService service = null;
ClientCredential credential= null;
try {
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(authority, true, service);
credential = new ClientCredential(clientId, clientSecret);
Future<AuthenticationResult> future = context.acquireToken(app_id_uri, credential,null);
result = future.get();
} finally {
service.shutdown();
}
String accessToken = null;
if (result == null) {
throw new ServiceUnavailableException("authentication result was null");
} else {
accessToken = result.getAccessToken();
System.out.println("Access Token: " + accessToken);
}
// Call to my rest service using above accessToken
}