SSO单点登录知识学习
1.概述
SSO(Single Sign On)单点登录是实现多个系统之间统一登录的验证系统,简单来说就是:有A,B,C三个系统,在A处登录过后,再访问B系统,B系统就已经处于了登录状态,C系统也是一样。
SSO简单来说就是一句话:一处登录,全部访问。下图是网上的一个关于SSO登录流程的图:
[图片上传失败...(image-2e5d17-1558878674308)]
1.1.登录流程跟踪分析
1.1.1.首次登录
Ssoclient:
[2019-05-26 20:58:53]http-apr-8585-exec-3-00039:[ssoclient]doFilter,getRequestURL:http://localhost:8585/webapp1/
Ssoclient:
[2019-05-26 20:59:18]http-apr-8585-exec-6-00042:[ssoclient]doFilter,getRequestURL:http://localhost:8585/webapp1/sysmainpage.jsp
[2019-05-26 20:59:18]http-apr-8585-exec-6-00042:[ssoclient]redirectUrl:http://localhost:8080/TechnicalAbilityToolBox?action=preLogin&setCookieURL=http://localhost:8585/webapp1/setCookie&gotoURL=http://localhost:8585/webapp1/sysmainpage.jsp
[2019-05-26 20:59:18]http-apr-8585-exec-6-00042:[ssoclient]not find cookie!
Ssoserver:
[2019-05-26 20:59:26]http-apr-8080-exec-3-00039:[ssoserver]doFilter,getRequestURL:http://localhost:8080/TechnicalAbilityToolBox/setCookie
[2019-05-26 20:59:26]http-apr-8080-exec-3-00039:[ssoserver]redirectUrl:http://localhost:8080/TechnicalAbilityToolBox?action=preLogin&setCookieURL=http://localhost:8080/TechnicalAbilityToolBox/setCookie&gotoURL=http://localhost:8585/webapp1/sysmainpage.jsp
[2019-05-26 20:59:26]http-apr-8080-exec-3-00039:[ssoserver]not find cookie!
[2019-05-26 20:59:26]http-apr-8080-exec-3-00039:[ssoserver]setCookie...
[2019-05-26 20:59:26]http-apr-8080-exec-3-00039:[ssoserver]setCookie ok,gotoUrl:http://localhost:8585/webapp1/sysmainpage.jsp
Ssoclient:
[2019-05-26 20:59:26]http-apr-8585-exec-8-00044:[ssoclient]doFilter,getRequestURL:http://localhost:8585/webapp1/sysmainpage.jsp
[2019-05-26 20:59:26]http-apr-8585-exec-8-00044:[ssoclient]redirectUrl:http://localhost:8080/TechnicalAbilityToolBox?action=preLogin&setCookieURL=http://localhost:8585/webapp1/setCookie&gotoURL=http://localhost:8585/webapp1/sysmainpage.jsp
[2019-05-26 20:59:26]http-apr-8585-exec-8-00044:[ssoclient]find cookie!
[2019-05-26 20:59:26]http-apr-8585-exec-8-00044:[ssoclient]authCookie...
[2019-05-26 20:59:26]http-apr-8585-exec-8-00044:[ssoclient]executeSSOPost...
Ssoserver:
[2019-05-26 20:59:26]http-apr-8080-exec-5-00041:[ssoserver]postAuth begin...
[2019-05-26 20:59:26]http-apr-8080-exec-5-00041:[ssoserver]postAuth end!
Ssoclient:
26-May-2019 20:59:26.420 WARNING [http-apr-8585-exec-8] org.apache.commons.httpclient.HttpMethodBase.getResponseBody Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.
[2019-05-26 20:59:26]http-apr-8585-exec-8-00044:[ssoclient]executeSSOPost ok!
[2019-05-26 21:00:37]http-apr-8585-exec-2-00038:[ssoclient]chain.doFilter(request, response) end!
1.1.2.二次登录
Ssoclient:
[2019-05-26 21:04:28]http-apr-8585-exec-10-00046:[ssoclient]doFilter,getRequestURL:http://localhost:8585/webapp1/sysmainpage.jsp
[2019-05-26 21:04:28]http-apr-8585-exec-10-00046:[ssoclient]redirectUrl:http://localhost:8080/TechnicalAbilityToolBox?action=preLogin&setCookieURL=http://localhost:8585/webapp1/setCookie&gotoURL=http://localhost:8585/webapp1/sysmainpage.jsp
[2019-05-26 21:04:28]http-apr-8585-exec-10-00046:[ssoclient]find cookie!
[2019-05-26 21:04:28]http-apr-8585-exec-10-00046:[ssoclient]authCookie...
[2019-05-26 21:04:28]http-apr-8585-exec-10-00046:[ssoclient]executeSSOPost...
Ssoserver:
[2019-05-26 21:04:28]http-apr-8080-exec-7-00043:[ssoserver]postAuth begin...
[2019-05-26 21:04:28]http-apr-8080-exec-7-00043:[ssoserver]postAuth end!
Ssoclient:
26-May-2019 21:04:28.390 WARNING [http-apr-8585-exec-10] org.apache.commons.httpclient.HttpMethodBase.getResponseBody Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.
[2019-05-26 21:04:28]http-apr-8585-exec-10-00046:[ssoclient]executeSSOPost ok!
[2019-05-26 21:05:37]http-apr-8585-exec-2-00038:[ssoclient]chain.doFilter(request, response) end!
2.****sso登录代码****分析
1.1.sso server
1.1.1.ssoLogin.jsp
<%--
Created by IntelliJ IDEA.
User: kikop
Date: 2019/5/21
Time: 8:02
To change this template use File | Settings | File Templates.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--引入 jstl 标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%--取出部署的应用程序名或者是当前的项目名称,等价于 request.getContextPath()--%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" scope="page"/>
<c:set var="gotoURL" value="${pageContext.request.getParameter('gotoURL')}" scope="page"/>
<html>
<body>
<h2>1.获取页面的gotoURL</h2>
<h2>2.输入账号进行sso登录</h2>
<h2>3.登录生成token,并返回业务系统</h2>
<h3>业务系统跳转地址:${gotoURL}</h3>
<%--获取页面的gotoURL=http://localhost:8585/webapp1/syspage.html--%>
<%--<a href="http://localhost:8080/TechnicalAbilityToolBox/setCookie?gotoURL=http://localhost:8585/webapp1/syspage.html">登录</a>--%>
<%--生成ticket和expiry--%>
<a href="http://localhost:8080/TechnicalAbilityToolBox/setCookie?gotoURL=${gotoURL}&ticket=hello&expiry=1800">登录</a>
</body>
</html>
1.1.2.****SSOServerAuth****Filter
package com.tech.ability.myssoserver;
import com.tech.ability.util.DateUtil;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONException;
import org.json.JSONObject;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
/**
-
单点登录管理中心服务端过滤器
-
<p>
-
Created by kikop on 2017/9/17.
*/
public class SSOServerAuth implements Filter {
private String ssoServerUrl;
private String ssoServerName;
/**
* 初始化
*
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//1.获取本机sso配置文件信息
this.ssoServerUrl = filterConfig.getInitParameter("ssoServerUrl");
this.ssoServerName = filterConfig.getInitParameter("ssoServerName");
}
/**
* 销毁
*/
@Override
public void destroy() {
}
/**
* 1.拦截请求
*
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//1.强转
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]doFilter,getRequestURL:"+request.getRequestURL()));
//2.操作
//2.1.得到请求资源路径
String contextPath = request.getContextPath(); //请求服务名: /TechnicalAbilityToolBox
String gotoURL = request.getParameter("gotoURL"); //webapp1的实际请求地址: /webapp1/syspage.html
if (gotoURL == null) { //获取请求页面本身
gotoURL = request.getRequestURL().toString(); //返回全路径: http://localhost:8080/TechnicalAbilityToolBox/login.jsp
}
String redirectUrl = ssoServerUrl + "?action=preLogin&setCookieURL=" + request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ contextPath + "/setCookie&gotoURL=" + gotoURL;
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]redirectUrl:"+redirectUrl));
//2.2.管理中心token的验证核心思路获取指定cookie
Cookie currentCookie = null;
Cookie[] cookies = request.getCookies(); //获取客户端的所有cookie,kk
boolean isFindCookie = false;
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(ssoServerName)) {
currentCookie = cookie;
isFindCookie = true;
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]find cookie!"));
break;
}
}
}
if (!isFindCookie) {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]not find cookie!"));
}
//3.放行,注意这里的逻辑顺序(命令优先)
if (request.getRequestURI().equals(contextPath + "/logout")) //1.login out用户退出
doLogout(request, response, filterChain, currentCookie, redirectUrl);
else if (currentCookie != null) //2.cookie 优先 token校验
authCookie(request, response, filterChain, currentCookie, redirectUrl);
else if (request.getRequestURI().equals(contextPath + "/setCookie")) //3.login in设置cookie
setCookie(request, response);
else //4.不再处理范围内,直接放行
response.sendRedirect(redirectUrl);
}
/**
* 3.设置Cookie
* key:ssoServerName,value:
*
* @param request
* @param response
* @throws IOException
*/
private void setCookie(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]setCookie..."));
//1.生成cookie并组装keyvalue参数
//Cookie currentCookie = new Cookie(ssoServerName, request.getParameter("ticket"));
Cookie currentCookie = new Cookie(ssoServerName, String.format("%s_token", UUID.randomUUID().toString()));
currentCookie.setPath("/"); //可以在webapp文件夹下的所有应用共享cookie
currentCookie.setMaxAge(30 * 60); //过期时间为半小时(单位:秒)
//2.追加到response
response.addCookie(currentCookie);
//3.读取应用app的地址
String gotoURL = request.getParameter("gotoURL");
//4.重定向app
if (gotoURL != null) {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]setCookie ok,gotoUrl:"+gotoURL));
response.sendRedirect(gotoURL);
}
}
/**
* 4.Cookie认证协议
*
* @param request
* @param response
* @param chain
* @param cookie
* @param redirectUrl
* @throws IOException
* @throws ServletException
*/
private void authCookie(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Cookie cookie, String redirectUrl) throws IOException, ServletException {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]authCookie..."));
NameValuePair[] params = new NameValuePair[2];
params[0] = new NameValuePair("action", "authTicket");
params[1] = new NameValuePair("ssoServerName", cookie.getValue());
try {
JSONObject result = executeSSOPost(request, response, chain, params);
if (result != null) {
if (result.has("success")) {
boolean success = result.getBoolean("success");
if (success) {
request.setAttribute("username", result.getString("username"));
request.setAttribute("userid", result.getString("userid"));
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]chain.doFilter(request, response) end!"));
chain.doFilter(request, response);
} else {
throw new RuntimeException("[ssoserver]auth token exception!");
}
} else {
throw new RuntimeException("[ssoserver]auth token exception!");
}
} else {
throw new RuntimeException("[ssoserver]auth token exception!");
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 5.退出协议
*
* @param request
* @param response
* @param chain
* @param cookie
* @param redirectUrl
* @throws IOException
* @throws ServletException
*/
private void doLogout(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Cookie cookie,
String redirectUrl) throws IOException, ServletException {
NameValuePair[] params = new NameValuePair[2];
params[0] = new NameValuePair("action", "logout");
params[1] = new NameValuePair("ssoServerName", cookie.getValue());
try {
executeSSOPost(request, response, chain, params);
} catch (JSONException ex) {
throw new RuntimeException(ex);
} finally {
//重定向到某app页面
response.sendRedirect(redirectUrl);
}
}
/**
* 2.执行Post请求
*
* @param request
* @param response
* @param chain
* @param params
* @return
* @throws IOException
* @throws ServletException
* @throws JSONException
*/
private JSONObject executeSSOPost(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, NameValuePair[] params)
throws IOException, ServletException, JSONException {
//1.请求管理中心,并设置请求参数
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(ssoServerUrl);
postMethod.addParameters(params);
switch (httpClient.executeMethod(postMethod)) {
case HttpStatus.SC_OK:
return new JSONObject(postMethod.getResponseBodyAsString());
default:
System.out.println("[ssoserver]executeMethod return null!");
return null;
}
}
}
1.1.3.MySSOAuth Controller
package com.tech.ability.springmvcstudy.mycontroller;
import com.alibaba.fastjson.JSONObject;
import com.tech.ability.util.DateUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
- Created by kikop on 2019/2/24.
*/
@Controller
@RequestMapping("/sso")
public class MySSOAuth {
@RequestMapping(value = "/postAuth.do", method = {RequestMethod.POST})
@ResponseBody
public JSONObject postAuth(HttpServletRequest request, HttpServletResponse response) {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]postAuth begin..."));
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("success", true);
jsonObject.put("username", "kikop");
jsonObject.put("userid", "123456");
} catch (Exception ex) {
ex.printStackTrace();
jsonObject.put("success", false);
}
System.out.println(DateUtil.getCurrentThreadInfo("[ssoserver]postAuth end!"));
return jsonObject;
}
//url http://localhost:8080/TechnicalAbilityToolBox/sso/getAuth.do?id=2
@RequestMapping(value = "/getAuth.do", method = {RequestMethod.GET})
@ResponseBody
public JSONObject getAuth(HttpServletRequest request, HttpServletResponse response, int id) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("success", true);
jsonObject.put("username", "kikop");
jsonObject.put("userid", "123456");
} catch (Exception ex) {
ex.printStackTrace();
jsonObject.put("success", false);
}
return jsonObject;
}
}
1.1.4.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>TechnicalAbilityToolBox Web Application</display-name>
<!--1.sso server认证-->
<filter>
<filter-name>SSOServerAuth</filter-name>
<!--业务处理逻辑-->
<filter-class>com.tech.ability.myssoserver.SSOServerAuth</filter-class>
<init-param>
<!--外部认证系统服务URL-->
<param-name>ssoServerUrl</param-name>
<param-value>http://localhost:8080/TechnicalAbilityToolBox</param-value>
</init-param>
<init-param>
<!-- 认证系统服务名称 -->
<param-name>ssoServerName</param-name>
<param-value>ssoname</param-value>
</init-param>
</filter>
<!--sso client 设置模式匹配内容(.jsp、/logout、/setCookie)-->
<!--放行ssologin.jsp-->
<!--<filter-mapping>-->
<!--<filter-name>SSOServerAuth</filter-name>-->
<!--<url-pattern>*.jsp</url-pattern>-->
<!--</filter-mapping>-->
<filter-mapping>
<filter-name>SSOServerAuth</filter-name>
<url-pattern>/authTicket</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SSOServerAuth</filter-name>
<url-pattern>/logout</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SSOServerAuth</filter-name>
<url-pattern>/setCookie</url-pattern>
</filter-mapping>
<!--2.spring容器加载-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--1.1.配置spring文件设置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:myspring/spring.xml</param-value>
</context-param>
<!--1.添加spring的一个servlet,定义前端控制器-->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定路径 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:/myspring/spring-servlet.xml
</param-value>
</init-param>
<!-- 随spring启动而启动 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--设置spring拦截-->
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--2.请求代理测试-->
<servlet>
<servlet-name>proxy</servlet-name>
<servlet-class>com.tech.ability.ProxyHandler</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>proxy</servlet-name>
<url-pattern>/proxy</url-pattern>
</servlet-mapping>
<!--3.配置字符编码过滤器-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<!-- /下的所有请求都为UTF-8编码 -->
<url-pattern>/</url-pattern>
</filter-mapping>
<!-- 7.防止Spring内存溢出监听器 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>ssologin.jsp</welcome-file>
</welcome-file-list>
</web-app>
1.2.sso client
[图片上传失败...(image-a6d70d-1558878674303)]
1.2.1.boot.jsp
<%--
Created by IntelliJ IDEA.
User: kikop
Date: 2019/5/21
Time: 8:02
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入 jstl 标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%--取出部署的应用程序名或者是当前的项目名称,等价于 request.getContextPath()--%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" scope="page"/>
<html>
<head>
<title>webapp1</title>
</head>
<body>
<a href="${contextPath}/sysmainpage.jsp">进入业务页面</a>
</body>
</html>
1.2.2.sysmainpage.jsp
<%--
Created by IntelliJ IDEA.
User: kikop
Date: 2019/5/26
Time: 18:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入 jstl 标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:set var="username" value="${pageContext.request.getParameter('username')}" scope="page"/>
<html>
<head>
<title>sysmainpage</title>
</head>
<body>
${username}成功登录!
</body>
</html>
1.2.3.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--1.sso client 认证-->
<filter>
<filter-name>SSOClientFilter</filter-name>
<!--业务处理逻辑-->
<filter-class>com.mysso.SSOClientFilter</filter-class>
<init-param>
<!--外部认证系统服务URL-->
<param-name>ssoServerUrl</param-name>
<param-value>http://localhost:8080/TechnicalAbilityToolBox</param-value>
</init-param>
<init-param>
<!-- 认证系统服务名称,服务端存储该key,value为:在管理中心登录后根据用户名,密码生成的token -->
<!-- 该token客户端获取到后,可以解析-->
<param-name>ssoServerName</param-name>
<param-value>ssoname</param-value>
</init-param>
</filter>
<!--sso client 设置模式匹配内容(.jsp、/logout、/setCookie)-->
<filter-mapping>
<filter-name>SSOClientFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
1.2.4.****SSOClientFilter
package com.mysso;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONException;
import org.json.JSONObject;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
/**
-
单点登录管理中心客户端过滤器
-
Created by kikop on 2017/9/17.
*/
public class SSOClientFilter implements Filter {
/**
* 单点服务的url
*/
private String ssoServerUrl;
private String ssoServerName;
/**
* 无需验证的path
*/
private static final HashSet<String> NOT_AUTH_PATH = new HashSet<String>();
/**
* 初始化
*
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
NOT_AUTH_PATH.add("/index.jsp");
//1.获取sso配置文件信息
this.ssoServerUrl = filterConfig.getInitParameter("ssoServerUrl");
this.ssoServerName = filterConfig.getInitParameter("ssoServerName");
}
/**
* 销毁
*/
@Override
public void destroy() {
}
/**
* 1.SSOClient拦截请求
*
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//1.强转
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//2.操作
//请求Example:
// http://localhost:8585/webapp1/syspage.html
//2.1.得到请求资源路径
String contextPath = request.getContextPath(); //请求服务名: /webapp1
//取得服务名后面的所有内容,去除斜/
//String requestURI = request.getRequestURI(); //返回除去host(域名或者ip)部分的路径
//String requestURIFollowsPath = requestURI.substring(contextPath.length() + 1);
String requestURL = request.getRequestURL().toString();
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]doFilter,getRequestURL:"+request.getRequestURL()));
String gotoURL = request.getParameter("gotoURL"); //webapp1的实际请求地址
if (gotoURL == null) { //没有,则获取请求页面本身
gotoURL = request.getRequestURL().toString(); //返回页面本身全路径: http://localhost:8585/webapp1/syspage.html
}
String not_auth_path = request.getServletPath();
if (NOT_AUTH_PATH.contains(not_auth_path)) {
filterChain.doFilter(request, response);
} else {
// 用户首次访问应用端,未携带cookie数据. 应用端会让用户重定向到服务器
String redirectUrl = ssoServerUrl + "?action=preLogin&setCookieURL=" + request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ contextPath + "/setCookie&gotoURL=" + gotoURL;
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]redirectUrl:"+redirectUrl));
//2.2.根据 ssoServerName 查找cookie是否有指定cookie(服务端也会验证)
Cookie currentCookie = null;
boolean isFindCookie = false;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(ssoServerName)) {
currentCookie = cookie;
isFindCookie = true;
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]find cookie!"));
break;
}
}
}
if (!isFindCookie) {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]not find cookie!"));
}
//3.处理逻辑(放行、注意这里的逻辑顺序)
if (request.getRequestURI().equals(contextPath + "/logout")) //1.login out用户退出
doLogout(request, response, filterChain, currentCookie, redirectUrl);
else if (currentCookie != null) //2.cookie 优先 token校验
authCookie(request, response, filterChain, currentCookie, redirectUrl);
else //3.登录管理中心验证
response.sendRedirect(redirectUrl);
}
}
/**
* 4.Cookie认证协议
*
* @param request
* @param response
* @param chain
* @param cookie
* @param redirectUrl
* @throws IOException
* @throws ServletException
*/
private void authCookie(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Cookie cookie, String redirectUrl) throws IOException, ServletException {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]authCookie..."));
NameValuePair[] params = new NameValuePair[2];
params[0] = new NameValuePair("action", "authTicket");
params[1] = new NameValuePair("ssoServerName", cookie.getValue());
try {
JSONObject result = executeSSOPost(request, response, chain, params);
if (result != null) {
if (result.has("success")) {
boolean success = result.getBoolean("success");
if (success) {
request.setAttribute("username", result.getString("username"));
request.setAttribute("userid", result.getString("userid"));
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]chain.doFilter(request, response) end!"));
chain.doFilter(request, response);
} else {
throw new RuntimeException("[ssoclient]auth token exception!");
}
} else {
throw new RuntimeException("[ssoclient]auth token exception!");
}
} else {
throw new RuntimeException("[ssoclient]auth token exception!");
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 2.执行Post请求
*
* @param request
* @param response
* @param chain
* @param params
* @return
* @throws IOException
* @throws ServletException
* @throws JSONException
*/
private JSONObject executeSSOPost(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, NameValuePair[] params)
throws IOException, ServletException, JSONException {
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]executeSSOPost..."));
//1.请求管理中心,并设置请求参数
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(ssoServerUrl + "/sso/postAuth.do");
postMethod.addParameters(params);
switch (httpClient.executeMethod(postMethod)) {
case HttpStatus.SC_OK:
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]executeSSOPost ok!"));
return new JSONObject(postMethod.getResponseBodyAsString());
default:
System.out.println(DateUtil.getCurrentThreadInfo("[ssoclient]executeSSOPost return null!"));
return null;
}
}
}
1.3.Util
1.3.1.DateUtil
package com.mysso;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
-
日期工具类
-
@author Administrator
*/
public class DateUtil {
/**
* 日期对象转字符串
*
* @param date
* @param format
* @return
*/
public static String formatDate(Date date, String format) {
String result = "";
SimpleDateFormat sdf = new SimpleDateFormat(format);
if (date != null) {
result = sdf.format(date);
}
return result;
}
/**
* 字符串转日期对象
*
* @param str
* @param format
* @return
* @throws Exception
*/
public static Date formatString(String str, String format) throws Exception {
if (StringUtil.isEmpty(str)) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.parse(str);
}
public static String getCurrentDateStr() {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
public static void isDoubleWeekDay() {
int isDoble = Calendar.DAY_OF_WEEK % 2;
System.out.println(isDoble);
}
/**
* 获取当前函数运行信息
*
* @param strMsg
* @return
*/
public static String getCurrentThreadInfo(String strMsg) {
return
String.format("[%s]%15s-%05d:%s ", getCurrentDateStr(), Thread.currentThread().getName(), Thread.currentThread().getId(),strMsg);
}
}
1.3.2.StringUtil
package com.mysso;
import java.util.ArrayList;
import java.util.List;
/**
-
字符串工具类
-
@author
*/
public class StringUtil {
/**
* 判断是否是空
*
* @param str
* @return
*/
public static boolean isEmpty(String str) {
if (str == null || "".equals(str.trim())) {
return true;
} else {
return false;
}
}
/**
* 判断是否不是空
*
* @param str
* @return
*/
public static boolean isNotEmpty(String str) {
if ((str != null) && !"".equals(str.trim())) {
return true;
} else {
return false;
}
}
/**
* 格式化模糊查询
*
* @param str
* @return
*/
public static String formatLike(String str) {
if (isNotEmpty(str)) {
return "%" + str + "%";
} else {
return null;
}
}
/**
* 过滤掉集合里的空格
*
* @param list
* @return
*/
public static List<String> filterWhite(List<String> list) {
List<String> resultList = new ArrayList<String>();
for (String l : list) {
if (isNotEmpty(l)) {
resultList.add(l);
}
}
return resultList;
}
}
3.web基础
3.1.request几种方式
request.getRequestURL() 返回全路径 request.getRequestURI() 返回除去host(域名或者ip)部分的路径 request.getContextPath() 返回工程名,如果工程映射为/,此处返回则为空 request.getServletPath() 返回除去host和工程名的路径 request.getRequestURL() http://localhost:8080/jqueryLearn/resources/request.jsp request.getRequestURI() /jqueryLearn/resources/request.jsp request.getContextPath()/jqueryLearn request.getServletPath()/resources/request.jsp
3.2.chrome浏览器中查看cookie
<u>chrome://settings/content/cookies</u>
<u>chrome://settings/cookies/detail?site=localhost</u>
[图片上传失败...(image-29ffde-1558878674296)]
[图片上传失败...(image-45ca51-1558878674296)]
3.3.cookie生命周期
cookie过期时间设置方式:
cookie.setMaxAge(0);//不记录cookie
cookie.setMaxAge(-1);//会话级cookie,关闭浏览器失效
cookie.setMaxAge(30*60);//过期时间为半小时(单位:秒)
Example:
<a href="http://localhost:8080/TechnicalAbilityToolBox/setCookie?gotoURL=${gotoURL}&ticket=hello&expiry=1800">登录</a>
currentCookie.setMaxAge(Integer.parseInt(request.getParameter("expiry")));
创建时间
2019年5月24日星期五 上午6:34:41
到期时间
2019年5月24日星期五 上午7:04:41
3.4.etc文件修改
C:\Windows\System32\drivers\etc
127.0.0.1 webapp1.com
127.0.0.1 webapp2.com
127.0.0.1 <u>www.mypassport.com</u>
3.5.scope取值(JSP)
page
request
session
application
参考
1.java实现完全跨域SSO单点登录
网友评论