要做个单点登陆的例子,要有以下:
1
用户身份认证服务器
2
两个应用系统。用户身份认证系统是提供认证功能和登陆功能的,应用系统是模拟跨域访问。项目结构如下图所示:
其中有三个项目:
Client
、
Client2
、
Server
。
Client
和
Client2
是应用系统用于模拟跨域访问的;而
Server
系统是用户身份验证的。三个都是
Web
工程。既然是
web
工程,那么众所周知
Web
协议(也就是
HTTP
)是一个无状态的协议。服务器是如何记录和保持登陆信息呢?
浏览器访问一次服务器,就和服务器建立一次
Sockect
连接当服务器响应完毕时,就会断口连接。第二次访问的时候模式一样。为了保存信息软件师们发明了两个东西:
Session
和
Cookie
。
Session
是保持在服务端的会话信息,
Cookie
是持久化在客户端的会话信息。浏览器每次访问
Web
站点时都把此站点相应的
Cookie
信息发送给服务器,服务器从
Cookie
中取相应的字段(
sessionId
),然后根据字段在服务器的缓存中查找相应的
Session
,如果没查到则
Request
对象会自动新建一个
Session
对象。这些是基础没有这些知识很难理解如何实现
SSO
的。
首先建好上面三个工程,然后各自建相应的过滤器和页面(源码
)可以先下载下来导入
Eclipse
中,启动
Tomcat
服务器。
第一:
client
端的
AuthFilter
代码
package org.hundsun.sso.filter.auth;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//登陆验证
public class AuthFilter implements Filter {
private String casUrl;
private String CASSERVER_URL;
private String SERVER_NAME;
private String VARERVER_URL;
private ConnectionUtil connectionUtil;
public void init(FilterConfig config) throws ServletException {
CASSERVER_URL=config.getInitParameter("casServer");
SERVER_NAME=config.getInitParameter("serverName");
VARERVER_URL=config.getInitParameter("varServer");
connectionUtil = new ConnectionUtil();
casUrl = new StringBuffer().append(CASSERVER_URL).append("?serverName=").append(SERVER_NAME).toString();
System.out.println(casUrl);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
HttpServletResponse response_ = (HttpServletResponse) response;
HttpServletRequest request_ = (HttpServletRequest) request;
//获得Ticket
String ticket = request.getParameter("ticket");
//转跳状态
boolean doFilter = false;
String CAS_USRR=(String)request_.getSession().getAttribute("CAS_USRR");
//如果已经登陆
if ( CAS_USRR!= null&&!"".equals(CAS_USRR)){
System.out.println("用户已经登录,转发用户请求");
System.out.println("CAS_USRR:"+CAS_USRR);
doFilter = true;
}
else
{
System.out.println("用户没有登录,验证用户ticket");
System.out.println("ticket详细如:"+ticket);
//Ticket不为空
String userName = null;
//解析用户信息
if (ticket != null && (userName = connectionUtil.getUserName(ticket)) != null) {
System.out.println("验证用户ticket成功!");
request_.getSession().setAttribute("CAS_USRR", userName);
doFilter = true;
}else{
System.out.println("验证用户ticket失败或ticket为空!");
}
}
if(doFilter)
chain.doFilter(request, response);
else {
//转跳到CAS服务器
System.out.println("用户没有登录且没携带ticket,转跳到CAS服务器登录验证!");
System.out.println("ticket验证地址:"+casUrl);
response_.sendRedirect(casUrl);
}
}
public void destroy() {
}
private class ConnectionUtil {
public String getUserName(String ticket) {
HttpURLConnection connection = null;
BufferedReader bfReader = null;
String userName = null;
try
{
//连接CAS验证服务器
System.out.println("连接CAS验证服务器!ticket:"+ticket);
String url=VARERVER_URL + "?ticket=" + ticket;
System.out.println("验证服务器URL:"+url);
connection = (HttpURLConnection) new URL(url).openConnection();
connection.connect();
bfReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
//获得解密后的用户名
userName = bfReader.readLine();
System.out.println("CAS验证服务器还回结果(userName):"+userName);
}
catch(Exception e)
{
throw new RuntimeException(e);
}
finally
{
try
{
if(bfReader!=null)bfReader.close();
if(connection!=null)connection.connect();
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
return userName;
}
}
}
这个是
client
端的验证用户是否登陆已经是否含有
tickect
信息的过滤器。
在上面的代码需要用到的参数在
web.xml
配置了,具体如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>autoFilter</filter-name>
<filter-class>org.hundsun.sso.filter.auth.AuthFilter</filter-class>
<init-param>
<param-name>casServer</param-name>
<param-value>http://127.0.0.1:8888/Server/login</param-value>
<description>认证服务器地址</description>
</init-param>
<init-param>
<param-name>varServer</param-name>
<param-value>http://127.0.0.1:8888/Server/server</param-value>
<description>服务器地址</description>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://127.0.0.1:8888/Client/welcome.jsp</param-value>
<description>跳转页面</description>
</init-param>
</filter>
<filter-mapping>
<filter-name>autoFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
其次也就是用户验证服务,有
LoginServer
和
ValidationServer
两个
Servlet
,
LoginServer
是检验用户
cookies
中是否含有
tickect
,然后重定向到验证服务中,而
ValidationServer
就是验证服务。
认证服务的配置信息在
web.xml
中:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<listener>
<listener-class>org.hundsun.sso.listener.KeyListener</listener-class>
</listener>
<servlet>
<servlet-name>LoginServer</servlet-name>
<servlet-class>org.hundsun.sso.service.LoginServer</servlet-class>
</servlet>
<servlet>
<servlet-name>ValidationServer</servlet-name>
<servlet-class>org.hundsun.sso.service.ValidationServer</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServer</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ValidationServer</servlet-name>
<url-pattern>/server</url-pattern>
</servlet-mapping>
</web-app>
LoginServer
代码:
public class LoginServer extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 发出请求的Client
String serverName = request.getParameter("serverName");
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies)
{
if (cookie.getName().equals("CAS")) {
// 生成Ticket
String ticket = "CAS" + ":" + cookie.getValue();
String url = new StringBuffer().append(serverName).append("?ticket=").append(ticket).toString();
response.sendRedirect(url);
return;
}
}
}
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
return;
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
ValidationServer
代码:
import org.hundsun.sso.utiil.RSAUtil;
//验证服务
public class ValidationServer extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String ticket = request.getParameter("ticket");
String serverName = request.getParameter("serverName");
String name = request.getParameter("name");
String pass = request.getParameter("pass");
//优先验证ticket信息
if(ticket!=null)
{
try {
System.out.println("收的的ticket为:"+ticket);
String[] result = ticket.split(":");
//验证服务器信息和密码
System.out.println("验证密码:"+result[0]);
System.out.println("验证信息:"+result[1]);
response.getWriter().print(result[1]);
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//验证表单登录信息
else
{
System.out.println("name:"+name);
System.out.println("pass"+pass);
//登陆成功后将信息保存到Cookie
Cookie cookie = new Cookie("CAS", name);
cookie.setMaxAge(-1);
response.addCookie(cookie);
String url = new StringBuffer().append(serverName).append("?ticket=").append("CAS" + ":" + name).toString();
response.sendRedirect(url);
return;
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
以上是代码,具体的流程序列图如:
运行下可以实现了传说中的
SSO
了。
- 大小: 201.3 KB
- 大小: 29.2 KB
分享到:
相关推荐
文章首先回顾了传统单站点登录的机制,即通过session和cookie记录用户登录状态,然后通过SSO的定义、应用场景以及业务需求来说明单点登录解决的现实问题。文章详细阐述了实现可完全跨域SSO的必要条件和功能实现,...
8. **虚拟现实与教育**:未来的教育可能会结合虚拟现实技术,使学生能够更直观地参与到像足球比赛这样的场景中,增强学习体验。 9. **社交媒体与分享**:技术使得学生可以更容易地分享他们的作品,得到反馈,促进...
根据提供的文件内容,本篇将详细阐述青岛版数学二年级下册的单元知识点。 第*单元讲授的是有余数的除法,涵盖了有余数除法的意义、余数与除数之间的关系,以及竖式计算方法。有余数的除法指的是在将物体平均分配时...
以下是从文档中提取的相关知识点: 1. **党员的担当精神**:党员在疫情防控中起到了核心作用,他们如同战斗堡垒,积极行动,展现出了强烈的使命意识和责任担当。南方医院的医护人员、警察以及社区工作者等都在前线...
为了实现这一目标,文章强调了选用面向对象方法的原因,这种方法能更好地捕捉现实世界的需求,并通过一个引进人才评估系统的例子说明其优越性。同时,文章还讨论了需求分析中使用多种工具和方法的重要性,以及正确...
这篇内容主要涉及的是语文教学中的写作技巧,特别是如何解读和运用寓言故事进行写作。寓言是一种常见的文学形式,通过简练的故事传达深刻的道理或教训。以下是几个关键知识点: 1. **寓言的特性**:寓言通常采用...
但是,我可以根据标题中的关键信息“基于模型的设计-MCU篇 514_ 44.4M 高清书签版”提供一些关于模型设计、MCU(微控制器单元)及其相关知识点的详细解释。 ### 基于模型的设计 **模型设计** 是一种工程设计方法论...
总的来说,这篇文章揭示了当前家庭教育中可能出现的问题,如过度关注学业成绩、忽视孩子的情感需求,同时也表达了孩子对理解和关爱的渴望。这些知识点对于家长和教育工作者来说,都是值得深思的议题,提醒他们在关注...
在【部分内容】中,提到了一些与阅读和学习方法相关的知识点: 1. **词语解释**: - "yí xiá jié jiáo chǎn ɡāo" (筹藻):这个词语在古代汉语中指的是修饰文辞,使文章更加华丽生动。 - "滞使心情愉快":...
【知识点解析】 这篇《我为什么而活着》是英国著名哲学家、数学家伯特兰·罗素的一篇散文,选自人教版八年级语文上册第四单元,旨在引导学生品味散文中的情理交融,揣摩深层含义,提升阅读与理解能力。罗素在文中...
高一数学知识点总结集锦15篇 本文总结了高一数学的重要知识点,包括函数及其表示、集合的概念和表示、函数的定义域和值域、集合的分类等。 高一数学学问点总结 1 函数及其表示 函数是数学中一个基本概念,通过...
在高考英语阅读理解的复习中,这篇关于“Escape Valve”的文章提供了一个社会现象的讨论点,让学生在学习语言的同时,也能思考人际关系和生活态度的问题。这种结合现实话题的文章有助于提高学生的批判性思维和分析...
【知识点详解】 1. 文章结构与主题分析: - 《答谢中书书》:文章以“山川之美,古来共谈”为总起,展现了古代文人对自然之美的共同热爱,随后通过描绘一系列自然景观,如山峰、水流、动植物等,构建出一幅宁静而...
这篇文档包含了两篇关于理想的发言稿,主要探讨了理想与现实、家庭与工作的平衡以及教师职业道德的议题。以下是这两篇发言稿中提炼出的关键知识点: 1. **理想与奉献**:发言稿提到了劳模们的无私奉献精神,尤其是...
由于直接提供文档扫描的OCR结果无法确保其准确性和连贯性,且由于指令要求不得提供OCR扫描内容,我将以给定的文件信息为基础,根据标题和描述生成相关知识点。 标题“基于模型的设计——MCU篇”指的是关于微控制器...
【知识点】 1. 高考英语复习:这个标题和描述提到了“2014届最新高考英语一轮单元复习”,表明这是一个针对高考英语复习的资料,重点在于提高学生的阅读理解能力,通过精选的文章来帮助学生备考。 2. 阅读理解提升...
论文着重分析了云门户在项目全生命周期管理中的作用,涵盖了过程管理、人员组织信息、单点登录(SSO)、待办待阅任务、邮件集成以及应用集成等多个方面。云门户通过集成这些功能,实现了项目管理的高效协同和信息...
【七年级语文上册第六单元知识点整理】 在七年级语文上册第六单元的学习中,我们聚焦于两篇文章:安徒生的童话《皇帝的新装》和郭沫若的诗歌《天上的街市》。这两篇作品都富含丰富的文学元素和深刻的主题。 1. **...