我正在尝试在基于Spring的Web应用程序中实现一个简单的SSO功能。场景:


我有一个主应用程序Application1和一个辅助Application2。两者都有自己的登录机制(使用spring-security登录表单)。
我想在Application1中实现SSO,以便用户登录到Application1时,他还可以通过链接无缝访问Application2,而不必填写Application2的登录详细信息。


这是我尝试过的:


我在Application2中创建了一个API,该API将电子邮件作为输入,对其进行验证,创建用户会话,并返回url字符串。

@RequestMapping(path = "/sso/login", consumes = "application/json", method = RequestMethod.POST)
public String login(@RequestBody SSOparams params, HttpServletRequest req, ModelMap model) {

// 1. validates email from params

// 2. creates Authentication object:
UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(username, password);
Authentication auth = authManager.authenticate(authReq);
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
HttpSession session = req.getSession(true);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc);

// 3. returns a url string:
return "/user/dashboard";
}

用户登录到Application1。
在Application1主页中,当用户单击Application2的链接时,将调用Application1的controller方法。
Application1的控制器方法使用email参数调用Application2的登录API,最后重定向到该API返回的URL。

Application1的控制器方法:

@RequestMapping(value = "/callapplication2", method = RequestMethod.POST)
public String callapplication2(ModelMap model,HttpSession session) {
String output = "";
String redirectionUrl = "";
try {
    // 1. calling application2's login API
    URL url = new URL("http://localhost:8080/application2/api/sso/login");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setDoOutput(true);
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type", "application/json");

    String input = "{\"uniqueemail\":\"[email protected]\"}";

    OutputStream os = conn.getOutputStream();
    os.write(input.getBytes());
    os.flush();
    BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
    while ((output = br.readLine()) != null) {
        redirectionUrl = redirectionUrl + output;
    }
    conn.disconnect();
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

 // 2. returns a url
return "redirect:http://localhost:8080/application2" + redirectionUrl ;
}



以上所有工作正常。但是,当我登录到Application1并单击application2的链接时,我希望应用程序应重定向到
http://localhost:8080/application2/user/dashboard
无需填写凭据。

但是,而是打开Application2的登录页面。我可以在Chrome的网络控制台中看到正在调用/user/dashboard,但是由于该页面是安全的,因此将我重定向到application2的登录页面。

这是否表示未使用我使用API​​创建的身份验证。我想念什么?

最佳答案

        Best approach is to set filter in web.xml and put it in top of the list.

        Whenever your application will get any request it will first go to the filter and there you will check that session is present or not if its null then simply redirect to your sso login page else respective landing page.

        Now in your case,
          Solution i can see

          1) Put filter into app2 web.xml

          2) Now when you redirect from app1 to app2 (Pass one parameter anything like username, email whatever)

          3) Store it into the session.

          4) Whenever any request will come to app2 you will first verify session from filter, If username found that means user not need to login again else redirect to sso login page.

          Thats standars steps (I belive)
          5) Having a peek into your implementation.Specifically you have to add one more step into app filter. When you are redirecting from app1 for te first time with http://localhost:8080/application2/user/dashboard ( You will pass one parameter along with this url as explained above).
          This let you to check 2 condition into your filter. Either request should have valid parameter or username should be into session. If any condition stated true you can let redirect request to further else you have to redirect to login page.

          Hope this will help to resolve your issue.

10-05 21:13