单点登陆分两种,一种是系统之间一级域名相同,如www.bbs.itcast.cn及www.news.itcast.cn这两个域名,一级域名(itcast.cn)相同,这两个系统可以拿到对方的cookie,通过cookie+Filter就能实现单点登录,另一种,如www.bbs.com及www.news.com,这两个网站没有任何关系,不在同一个域中。这种情况下节再讲。
首先eclipse创建一个web工程,这里写一个简单的登陆页面,这里直接修改index.jsp作为登录页:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<c:choose>
<c:when test="${not empty sessionScope.user}">
欢迎你:${sessionScope.user}
</c:when>
<c:otherwise>
你还没有登录,请先登录:
<form action="<%=path %>/login" method="post">
userName:<input type="text" name="userName"><br>
password:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</c:otherwise>
</c:choose>
</body>
</html>
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<c:choose>
<c:when test="${not empty sessionScope.user}">
欢迎你:${sessionScope.user}
</c:when>
<c:otherwise>
你还没有登录,请先登录:
<form action="<%=path %>/login" method="post">
userName:<input type="text" name="userName"><br>
password:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</c:otherwise>
</c:choose>
</body>
</html>
然后写一个servlet接收该请求:
public class LoginServlet extends HttpServlet {
/**
* Constructor of the object.
*/
public LoginServlet() {
super();
}
* Constructor of the object.
*/
public LoginServlet() {
super();
}
/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
}
/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
if(userName != null && password != null){
if(userName.equals(password)){//登录成功,实际应查询数据库
request.getSession().setAttribute("user", userName);
//向客户端写入cookie
Cookie c = new Cookie("sso",userName);
c.setMaxAge(3600);//1小时
c.setDomain(".itcast.cn");//www.bbs.itcast.cn www.news.itcast.cn
c.setPath("/");
response.addCookie(c);
}
}
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
String password = request.getParameter("password");
if(userName != null && password != null){
if(userName.equals(password)){//登录成功,实际应查询数据库
request.getSession().setAttribute("user", userName);
//向客户端写入cookie
Cookie c = new Cookie("sso",userName);
c.setMaxAge(3600);//1小时
c.setDomain(".itcast.cn");//www.bbs.itcast.cn www.news.itcast.cn
c.setPath("/");
response.addCookie(c);
}
}
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}
说明:c.setDomain(".itcast.cn");设置cookie的域,这样的话所有一级域名为itcast.cn的系统都能拿到这个cookie.
c.setPath("/");表示部署在同一服务器下的应用都能拿到这个cookie,如果写成c.setPath("/sso_bbs");那只有这个sso_bbs的应用能拿到这个cookie.
这时候我们默认访问localhost:8080/index.jsp,虽然能正确访问页面,但是发现浏览器并没有记录名字为“sso"的cookie,这是为什么,因为我们设置了这个cookie的domain一级域名只能是itcast.cn,而我们访问的并不是这样一个地址,所以没有产生cookie,所以需要访问类似www.bbs.itcast.cn这样的网址才行,但是现在这样访问肯定不行。
所以我们还需要修改一些配置,首先修改系统hosts文件:
增加最下面这一行,这时候去访问www.bbs.itcast.cn,发现还是找不到应用服务器的项目资源,而输入localhost为什么就可以访问(这里设置工程访问端口为80,免去输入指定的端口)。这是因为在访问localhost时候tomact服务器会默认去webapps中访问项目资源,所以我们需要去修改tomact中的配置文件,打开tomact安装目录下的conf的server.xml文件找到Host节点,有如下配置,这就是为什么在访问localhost的时候,能访问到项目资源的原因:
修改配置文件:
当然为了不影响tomact原始逻辑,可以选择不修改原有节点,而是增加一个Host节点:
修改完配置文件,然后在tomact的与webapps平级的目录下创建bbs目录,将项目拷贝到bbs目录,将项目目录重命名为bbs,这时候访问www.bbs.itcast.cn/bbs就可以了,但是为了方便,不想加bbs这样的项目目录后缀,那么要怎样改呢?
大家会发现,当我们访问启动tomact的时候,直接访问localhost,可以进到tomact的首页,为什么这里不需要加项目后缀,这是因为这个资源在webapps下的ROOT目录下,tomact默认,当不写项目后缀的情况下,tomact默认加载ROOT目录下的资源,所以,很简单,我们只需要将刚才重命名为bbs的目录命名为ROOT,这时候直接访问www.bbs.itcast.cn就可以访问到项目了。
现在我们先实现一个单点登录无关的功能,就是“记住我”。这样的功能,也就是当一个用户第一次登陆了,关闭浏览器,过一段时间去访问网站,无需再次登录。
这个实现的思路大致是,写一个过滤器,遍历cookie,当存在我们登陆时写入的cookie,就设置session属性。过滤器代码如下:
public class AutoLoginFilter implements Filter {
public void destroy() {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if(request.getSession().getAttribute("user")== null){
Cookie[] cs = request.getCookies();
if(request.getSession().getAttribute("user")== null){
Cookie[] cs = request.getCookies();
if (cs != null && cs.length > 0) {
for (Cookie c : cs) {
String cName = c.getName();
if (cName.equals("sso")) {
String userName = c.getValue();
request.getSession().setAttribute("user", userName);
}
}
}
}
for (Cookie c : cs) {
String cName = c.getName();
if (cName.equals("sso")) {
String userName = c.getValue();
request.getSession().setAttribute("user", userName);
}
}
}
}
chain.doFilter(request, resp);
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
}
}
然后在web,xml配置过滤器:
<filter>
<filter-name>autoLogin</filter-name>
<filter-class>cn.itcast.sso.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>autoLogin</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-name>autoLogin</filter-name>
<filter-class>cn.itcast.sso.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>autoLogin</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这样就实现了“记住我”这种功能。然后为了验证单点登录,可以再新建一个工程,代码可以跟之前工程类似,只需改一下登陆成功返回的页面显示,以区分之前的项目。在hosts中新增映射:
然后修改在tomact配置文件中再新增一个Host节点:
然后将新建的工程放入news目录中,修改项目名称为ROOT,再访问www.news.itcast.cn,发现无需登录。