HttpUtil
public class HttpUtil {
/**
* 模拟浏览器的请求
* @param httpURL 发送请求的地址
* @param params 请求参数
* @return
* @throws Exception
*/
public static String sendHttpRequest(String httpURL,Map<String,String> 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<String,String> 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();
}
}
SSOClientUtil
public class SSOClientUtil {
//统一认证中心地址(域名)
public static final String SERVER_DOMAIN="http://www.sso.com";
//统一认证中心检查是否已经登录的访问地址
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";
//统一认证中心的token认证方法的jsessionid参数名
public static final String JSESSIONID="jsessionid";
/**
* 获取客户端的完整登出地址 http://www.client1.com:8081/logOut
* @return
*/
public static String getClientLogOutUrl(HttpServletRequest request){
//获取请求使用的协议,是http或者https
String scheme = request.getScheme();
//获取主机的名字 www.client1.com
String serverName = request.getServerName();
//获取请求的端口号 8081
int serverPort = request.getServerPort();
//获取请求URL
String servletPath = request.getServletPath();
String url = scheme+"://"+serverName+":"+serverPort+CLIENT_LOGOUT_URL;
return url;
}
/**
* 获取认证中心的登出地址 http://www.sso.com/logOut
* @return
*/
public static String getServerLogOutUrl(){
String serverURL = SERVER_DOMAIN;
String logOutURL = SERVER_LOGOUT_URL;
return serverURL+logOutURL;
}
/**
* 当客户端请求被拦截,跳往统一认证中心,需要带redirectUrl的参数,统一认证中心登录后回调的地址
* 通过Request获取这次请求的地址 http://www.client1.com:8081/main
*
* @param request
* @return
*/
public static String getRedirectUrl(HttpServletRequest request){
//获取请求使用的协议,是http或者https
String scheme = request.getScheme();
//获取主机的名字 www.client1.com
String serverName = request.getServerName();
//获取请求的端口号 8081
int serverPort = request.getServerPort();
//获取请求URL
String servletPath = request.getServletPath();
String url = scheme+"://"+serverName+":"+serverPort+servletPath;
return url;
}
/**
* 根据request获取跳转到统一认证中心的地址 http://www.sso.com//checkLogin?redirectUrl=http://www.client1.com:8081/main
* 通过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 = getRedirectUrl(request);
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<String,String> params = new HashMap<String,String>();
params.put(TOKEN_NAME, token);
params.put(CLIENTURL, clientURL);
params.put(JSESSIONID, jsessionid);
try {
String responseContent = HttpUtil.sendHttpRequest(serverURL+verifyURL, params);
if("true".endsWith(responseContent)){
return true;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return false;
}
}
LoginFilter
public class LoginFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//判断局部会话,看是否有登陆状态
Object isLogin = request.getSession().getAttribute("isLogin");
if(isLogin!=null&&(Boolean)isLogin){
//直接放行
chain.doFilter(request, response);
return;
}
//判断参数是否有token
Object token = request.getParameter("token");
if(token!=null&&StringUtils.isNoneEmpty((String)token)){
//如果有则进行校验
boolean result = SSOClientUtil.verify((String)token,
SSOClientUtil.getClientLogOutUrl(request), request.getSession().getId());
if(result){
//创建局部会话
request.getSession().setAttribute("isLogin",true);
//直接放行
//chain.doFilter(request, response);
response.sendRedirect("/main");
return;
}
}
//跳转到认证中心进行验证(看是否有其他系统登陆过)
//www.server.com/checkLogin
//通过http请求来访问认证中心
SSOClientUtil.redirectToSSOURL(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
SSO Login
@Controller
public class LoginContrller {
@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 "login";
}
@RequestMapping("/login")
public String login(String username, String password, String redirectUrl, Model model, HttpSession session){
//做账号密码验证,如果验证成功需要重定向到客户端
if("zhangsan".equals(username)&&"666".equals(password)){
//创建令牌
String token = UUID.randomUUID().toString();
//创建全局会话
session.setAttribute("token",token);
//放入map中(只要存在map中的token都是合法的)
SSOServerUtil.map.put(token,new ArrayList<String[]>());
//把令牌传给客户端
model.addAttribute("token",token);
return "redirect:"+redirectUrl;
}
model.addAttribute("errorMsg","账号或密码错误!");
model.addAttribute("redirectUrl",redirectUrl);
return "login";
}
@RequestMapping("/verify")
@ResponseBody
public String verify(String token,String clientURL,String jsessionid){
//验证token是否合法
ArrayList<String[]> list = SSOServerUtil.map.get(token);
if(list!=null){
//合法(注册系统)
list.add(new String[]{clientURL,jsessionid});
return "true";
}
//不合法
return "false";
}
@RequestMapping("/logOut")
public String logOut(HttpSession session) throws Exception {
//注销全局会话
session.invalidate();
return "login";
}
}