1、Client1-创建客户端client1项目(java web项目)
对应pom.xml引入
junit
junit
4.11
test
javax.servlet
javax.servlet-api
3.0.1
provided
org.springframework
spring-webmvc
4.2.3.RELEASE
2、Client1-新建LoginFilter文件,在这里doFilter方法中目前先直接放行
package com.sso.client1.filter;
import com.sso.client1.util.SSOClientUtil;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @param
* @Author wangbin
* @description
* @CreateDate 2019/6/21
* @return
*/
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//直接放行
chain.doFilter(request,response);
return;
}
@Override
public void destroy() {
}
}
3、Client1-web.xml配置文件添加LoginFilter过滤器,拦截所有的请求
Archetype Created Web Application
loginFilter
com.sso.client1.filter.LoginFilter
loginFilter
/*
4、Client1-添加一个index.jsp作为首页,直接放在webapp目录下(不要放WEB-INF目录)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
客户端1
客户端1的首页
客户端1端口号为8011
点击下面按钮退出登录
退出
5、Client1-配置client1项目的tomcat,将http端口号设置为8011,为防止后面项目端口冲突,把JMX PORT端口号也改了
6、Client1-启动项目,到此能正常启动,访问localhost:8011/index.jsp能正常看到页面即可
7、Client1-完善过滤器的执行方法,具体的流程步骤都写在代码注释里面,里面用到SSOClientUtil工具类去判断token是否有效,后面会放上,这里不应该注重是如何判断的,而是应该注重这里需要去判断
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
//判断是否有局部会话
HttpSession session = req.getSession();
Object isLogin = session.getAttribute("isLogin");
if(isLogin!=null && (Boolean) isLogin){
//已经登录则直接放行访问页面
chain.doFilter(request,response);
return;
}
//未登录
//判断是否有令牌(如果有则进行校验)
String token = request.getParameter("token");
if (token != null){
//确认令牌token是否有效.
Boolean verify = SSOClientUtil.verify(token, SSOClientUtil.getUrl(req,SSOClientUtil.CLIENTURL), session.getId());
if (verify){
//token有效,创建局部会话设置登录状态,并放行
session.setAttribute("isLogin",true);
chain.doFilter(request,response);
return;
}
}
//如果没有token,或者token无效
//去认证中心验证是否有登录状态,可能其他系统已经登录了
SSOClientUtil.redirectToSSOURL(req,resp);
}
8、附上两个Util类
(1)SSOClientUtil.java
package com.sso.client1.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class SSOClientUtil {
//统一认证中心地址(域名)
public static final String SERVER_DOMAIN="http://localhost:8080";
//统一认证中心检查是否已经登录的访问地址
public static final String SERVER_CHECK_URL="/checkLogin?redirectUrl=";
//统一认证中心的token认证地址
public static final String SERVER_VERIFY_URL="/verify";
//统一认证中心的登出地址
public static final String SERVER_LOGOUT_URL="/logOut";
//客户端的登出地址
public static final String CLIENT_LOGOUT_URL="/logOut";
//统一认证中心的token认证方法的token参数名
public static final String TOKEN_NAME="token";
//统一认证中心的token认证方法的登出地址参数名
public static final String CLIENTURL="clientURL";
//获取客户端重定向地址
public static final String REDIRECT_URL="redirectURL";
//统一认证中心的token认证方法的jsessionid参数名
public static final String JSESSIONID="jsessionid";
/**
* 获取客户端的登出地址 http://localhost:8011/logOut
* 获取客户端的重定向地址 http://localhost:8011/index.jsp
* 获取认证中心登出地址 http://localhost:8080/logOut
* @return
*/
public static String getUrl(HttpServletRequest request, String name){
//获取请求协议,是http或者https
String scheme = request.getScheme();
//获取主机
String host = request.getServerName();
//获取端口号
int port = request.getServerPort();
//获取请求地址
String servletPath = request.getServletPath();
if(name != null && (CLIENTURL.equals(name)||name==CLIENTURL)){
//返回客户端登出地址
return scheme + "://" + host + ":" + port + CLIENT_LOGOUT_URL;
}else if(name != null && (REDIRECT_URL.equals(name)||name==REDIRECT_URL)){
//返回客户端重定向地址
return scheme + "://"+host + ":"+port + servletPath;
}else if(name != null && (SERVER_LOGOUT_URL.equals(name)||name==SERVER_LOGOUT_URL)){
//返回认证中心登出地址
String serverURL = SERVER_DOMAIN;
String logOutURL = SERVER_LOGOUT_URL;
return serverURL+logOutURL;
}
return "";
}
/**
* 根据request获取跳转到统一认证中心的地址
* http://localhost:8080/checkLogin?redirectUrl=http://localhost:8011/index.jsp
* 通过Response跳转到指定的地址
* @param request
* @param response
* @throws IOException
*/
public static void redirectToSSOURL(HttpServletRequest request,HttpServletResponse response) throws IOException{
String serverURL = SERVER_DOMAIN;
String checkURL = SERVER_CHECK_URL;
String redirectUrl = getUrl(request,REDIRECT_URL);
StringBuilder url = new StringBuilder(50);
url.append(serverURL).append(checkURL).append(redirectUrl);
response.sendRedirect(url.toString());
}
/**
* 验证token是否有效
* 如果有效把客户端的登出地址和jsessionid传递到统一认证中心,方便进行单点注销.
* @param token
* @param clientURL
* @param jsessionid
* @return
*/
public static Boolean verify(String token, String clientURL,String jsessionid) {
String serverURL = SERVER_DOMAIN;
String verifyURL = SERVER_VERIFY_URL;
Map params = new HashMap();
params.put(TOKEN_NAME, token);
params.put(CLIENTURL, clientURL);
params.put(JSESSIONID, jsessionid);
try {
//判断token是否有效,直接发送一个带上token参数的请求到认证中心
//根据返回结果判断是否有效
String responseContent = HttpUtil.sendHttpRequest(serverURL+verifyURL, params);
if("true".endsWith(responseContent)){
return true;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return false;
}
}
(2)HttpUtil.java
package com.sso.client1.util;
import org.springframework.util.StreamUtils;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Map.Entry;
public class HttpUtil {
/**
* 模拟浏览器的请求
* @param httpURL 发送请求的地址
* @param params 请求参数
* @return
* @throws Exception
*/
public static String sendHttpRequest(String httpURL,Map params) throws Exception{
//建立URL连接对象
URL url = new URL(httpURL);
//创建连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求的方式(需要是大写的)
conn.setRequestMethod("POST");
//设置需要响应结果
conn.setDoOutput(true);
//判断是否有参数.
if(params!=null&¶ms.size()>0){
StringBuilder sb = new StringBuilder();
for(Entry entry:params.entrySet()){
sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());
}
//sb.substring(1)去除最前面的&
conn.getOutputStream().write(sb.substring(1).toString().getBytes("utf-8"));
}
//发送请求到服务器
conn.connect();
//获取远程响应的内容.
String responseContent = StreamUtils.copyToString(conn.getInputStream(),Charset.forName("utf-8"));
conn.disconnect();
return responseContent;
}
/**
* 模拟浏览器的请求
* @param httpURL 发送请求的地址
* @param jesssionId 会话Id
* @return
* @throws Exception
*/
public static void sendHttpRequest(String httpURL,String jesssionId) throws Exception{
//建立URL连接对象
URL url = new URL(httpURL);
//创建连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求的方式(需要是大写的)
conn.setRequestMethod("POST");
//设置需要响应结果
conn.setDoOutput(true);
conn.addRequestProperty("Cookie","JSESSIONID="+jesssionId);
//发送请求到服务器
conn.connect();
conn.getInputStream();
conn.disconnect();
}
}
9、重启项目,访问localhost:8011/index.jsp,会检查到未登录,然后跳转到认证中心去检查是否有登录状态,这里因为还没写认证中心的项目,所有访问会出错,但是能看到已经跳转,并且带上了重定向地址
10、到此已经完成client1项目登录的代码(还有部分登出注销的逻辑,后面补上)
11、同样的方法创建server项目,项目结构如下
12、附上web.xml文件,以及pom.xml依赖部分、applicationContext.xml
Archetype Created Web Application
SpringMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:applicationContext.xml
1
SpringMVC
/
javax.servlet
servlet-api
2.5
provided
javax.servlet
jstl
1.1.2
taglibs
standard
1.1.2
org.springframework
spring-webmvc
4.2.3.RELEASE
13、LoginController的checkLogin方法、login方法、verity方法
package com.sso.server.controller;
import com.sso.server.util.HttpUtil;
import com.sso.server.util.SSOServerUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
import java.util.*;
@Controller
public class LoginController {
/**
* 检查是否有登录状态
* @param redirectUrl
* @return
*/
@RequestMapping("checkLogin")
public String checkLogin(String redirectUrl,Model model,HttpSession session){
//判断是否有其他系统登录过(判断是否有全局会话)
Object token = session.getAttribute("token");
if(token!=null){
//重定向到应用系统,并且带上令牌
model.addAttribute("token",token);
return "redirect:"+redirectUrl;
}
model.addAttribute("redirectUrl",redirectUrl);
//跳转到登录页面
return "forward:/login.jsp";
}
/**
* 登录表单提交的方法
* @param redirectUrl
* @return
*/
@RequestMapping("login")
public String login(String redirectUrl, String username, String password, Model model, HttpSession session){
if(username.equals("admin")&&password.equals("1")){
//登录成功
//1.创建令牌
String token = UUID.randomUUID().toString();
//2.把令牌放到全局会话中
session.setAttribute("token",token);
//3.放到map容器中(只要存在该容器中的token都是合法的)
SSOServerUtil.map.put(token,new ArrayList
14、还没写完
15、写篇博客真是不简单
16、源码丢了,改天再写一个?