单点登陆实现

单点登录的简单实现

实现的原理:

  所有子系统的登录全部交由一个登录系统去实现,登录成功后生成一个ticket,并将ticket和用户名作为一个键值对保存在登录系统中,同时将用户名保存在cookie中。然后重定向回到原来的请求路径,子系统会根据ticket请求登录系统获取用户名,成功后,登录系统删掉ticket和用户名,并将用户名保存在session中,当session中有用户名后不会再被过滤重定向到登录系统。

  当一个子系统登录成功后,请求其他子系统时,session中并没有用户名会重定向到登录系统,登录系统会获取cookie中的用户名,获取到用户名后会生成一个ticket,再次将ticket和用户名作为一个键值对保存在登录系统中,并再重定向会原来的请求并携带上ticket,此时就会根据ticket请求登录系统获取用户名,并存入session。

  登出时只需要删除cookie,并在子系统做判断,当session中用户名与cookie中用户名不一致时,则认为没有登录,要求重新登录即可。

 

实现步骤:

  因为需要同时启动3个项目(不同的端口号),一个登录系统,两个子系统,使用tomcat不太方便,这里使用的是jetty插件。

  在pom.xml文件中进行配置,然后使用maven build启动即可。

<plugins>  

      <plugin>  

          <groupId>org.mortbay.jetty</groupId>  

          <artifactId>jetty-maven-plugin</artifactId>  

          <version>8.1.9.v20130131</version>  

          <configuration>  

              <stopKey>stop</stopKey>  

              <stopPort>6001</stopPort>   <!--  3个项目的端口号都不相同   -->

              <webAppConfig>  

                  <contextPath>/client1</contextPath>  

              </webAppConfig>  

              <scanIntervalSeconds>4</scanIntervalSeconds>  

              <connectors>  

                  <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">  

                      <port>8082</port>   <!--  3个项目的端口号都不相同   -->

                      <maxIdleTime>60000</maxIdleTime>  

                  </connector>  

              </connectors>  

          </configuration>  

      </plugin>  

</plugins>  

 

 

登录系统:

登录效验:

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  String username = req.getParameter("username"); 
  String password = req.getParameter("password"); 
  String service = req.getParameter("service");//原来请求的路径 
  /**
  * 此处应该访问数据库效验用户
  * */
  if ("test".equals(username) && "test".equals(password)) { 
  Cookie cookie = new Cookie("sso", username);//效验通过,将用户名存入cookie 
  cookie.setPath("/"); //设置的cookie路径 
  resp.addCookie(cookie); //写入客户端
  long time = System.currentTimeMillis(); 
  String timeString = username + time; //生成ticket凭证
  JVMCache.TICKET_AND_NAME.put(timeString, username); //存入缓存
  /**
  * 将ticket返回给原请求地址(登录效验)
  * */
  if (null != service) { 
  StringBuilder url = new StringBuilder(); 
  url.append(service); 
  if (0 <= service.indexOf("?")) { 
  url.append("&"); 
  } else { 
  url.append("?"); 
  } 
  url.append("ticket=").append(timeString); 
  resp.sendRedirect(url.toString()); //请求原路径
  } else { 
  resp.sendRedirect("/ssoServer/index.jsp"); //请求登录页面
  } 
  } else { 
  resp.sendRedirect("/ssoServer/index.jsp?service=" + service); 
  } 
}

过滤所有请求

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
  HttpServletRequest request = (HttpServletRequest) servletRequest; 
  HttpServletResponse response = (HttpServletResponse) servletResponse; 
  String service = request.getParameter("service"); //获取要访问的原地址 
  String ticket = request.getParameter("ticket"); //获取凭证
  //获取cookie中的用户名
  Cookie[] cookies = request.getCookies(); 
  String username = ""; 
  if (null != cookies) { 
  for (Cookie cookie : cookies) { 
  if ("sso".equals(cookie.getName())) { 
    username = cookie.getValue(); 
    break; 
    } 
   } 
 } 
//ticket不为空时,为子系统在效验是否登录
if (null == service && null != ticket) { 
  filterChain.doFilter(servletRequest, servletResponse); 
  return; 

/**
* 用户已经登录
* */
if (null != username && !"".equals(username)) { 
  long time = System.currentTimeMillis(); 
  String timeString = username + time; //生成ticket凭证
  JVMCache.TICKET_AND_NAME.put(timeString, username); //存入缓存
  StringBuilder url = new StringBuilder();
  /**
  * 重新生成token与用户名的缓存,并执行原请求(登录效验)
  * */
  url.append(service); 
  if (0 <= service.indexOf("?")) { 
    url.append("&"); 
  } else { 
    url.append("?"); 
  } 
  url.append("ticket=").append(timeString); 
    response.sendRedirect(url.toString()); //请求原路径并携带上ticket
  } else { 
    filterChain.doFilter(servletRequest, servletResponse); 
  } 
}

返回用户名

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  /**
  * 通过效验ticket,返回给子系统用户名
  * */
  String ticket = req.getParameter("ticket"); 
  String username = JVMCache.TICKET_AND_NAME.get(ticket); 
  JVMCache.TICKET_AND_NAME.remove(ticket);
  //不为空时才返回
  if(null!=username&&!"".equals(username)){
    PrintWriter writer = resp.getWriter(); 
    writer.write(username);
  }
}

 

子系统:

/**
* 过滤所有请求,判断用户是否登录
* */
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
  HttpServletRequest request = (HttpServletRequest) servletRequest; 
  HttpServletResponse response = (HttpServletResponse) servletResponse; 
  HttpSession session = request.getSession(); 
  String username = (String) session.getAttribute("username"); //获取session里的用户名
  String ticket = request.getParameter("ticket"); //获取ticket
  String url = URLEncoder.encode(request.getRequestURL().toString(), "UTF-8"); 
  //获取cookies里面的用户名
  Cookie[] cookies = request.getCookies(); 
  String tempname = ""; 
  if (null != cookies) { 
    for (Cookie cookie : cookies) { 
      if ("sso".equals(cookie.getName())) { 
        tempname = cookie.getValue(); 
        break; 
      } 
    } 
  } 
  //用户名为空说明未登录
  if (null == username||!tempname.equals(username)) { //cookie和session用户名不一致说明已经登出 
    if (null != ticket && !"".equals(ticket)) {
    //通过ticket向登录服务器发送请求获取对应用户名
    PostMethod postMethod = new PostMethod("http://localhost:8081/ssoServer/ticket"); 
    postMethod.addParameter("ticket", ticket); 
    HttpClient httpClient = new HttpClient(); 
    try { 
      httpClient.executeMethod(postMethod); 
      username = postMethod.getResponseBodyAsString();
      postMethod.releaseConnection(); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  //用户名不为空说明已经登录,执行原请求
  if (null != username && !"".equals(username)) { 
    session.setAttribute("username", username); 
    filterChain.doFilter(request, response); 
  } else { //用户名为空,未登录,跳转到登录页面
    response.sendRedirect("http://localhost:8081/ssoServer/index.jsp?service=" + url); 
  } 
} else { //用户名为空,未登录,跳转到登录页面
  response.sendRedirect("http://localhost:8081/ssoServer/index.jsp?service=" + url); 

} else { //已登录,执行原请求
  filterChain.doFilter(request, response); 

}

转载于:https://my.oschina.net/zhanggc/blog/1635928

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值