客户端和服务器建立联系以后就会将sessionid写入cookie,当客户端关闭后cookie就会被清除同时服务器端session也会被销毁。所以我们登录到服务器后可以在cookie中写入我们的登录信息用于访问其他页面时做登录校验。这种校验方法和把登录后信息写入session中道理基本一样。
java单点登录利用了cookie机制。每个客户端系统都维护自己的cookie登录信息,但是在其中的一个系统中登录了,怎样将登录信息写入其他客户端系统呢?另外cookie中登录信息的校验和登录时用户名密码的校验又怎么处理呢?单点登录一般在访问客户端主页面的时候,客户端的controller在接受到访问时,首先查看本域的cookie中有没有登录信息,当发现cookie中没有登录信息户就会返回校验服务器login页面。当发现cookie中存在登录信息后,该客户端会将登录信息发送给校验服务器,后根据校验服务器返回的校验结果决定返回成功登录页面或者校验服务器login页面。另外在登录成功后需要写cookie的时候,调用所有客户端的写cookie方法。这样所有客户端cookie的登录信息都被写入,在其他客户端访问主页面时发现cookie中有了登录信息,然后拿着这个信息去校验服务器进行校验。这样就可以成功访问主页面而不用登录了。
工程结构
ServerLoginController.java
package www.checkServer.com.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import www.checkServer.com.util.CheckUtil;
@Controller
@RequestMapping("/server")
public class ServerLoginController {
@Autowired
HttpServletResponse response;
/**
* 统一登录
* @param form
* @return
* @throws IOException
*/
@ResponseBody
@RequestMapping("/doLogin")
public void doLogin(String username,String password) throws IOException{
boolean ok = CheckUtil.checkLogin(username, password);
String result = "0";
if(ok){
result = "1";
}
response.getWriter().println(result);
response.getWriter().close();
}
/**
* 统一cookie校验
* @param cookieName
* @param cookieValue
* @throws IOException
*/
@ResponseBody
@RequestMapping("/checkCookie")
public void checkCookie(String cookieName,String cookieValue) throws IOException{
boolean ok = CheckUtil.checkCookie(cookieName, cookieValue);
String result = "0";
if(ok){
result = "1";
}
response.getWriter().println(result);
response.getWriter().close();
}
}
CheckUtil.java
package www.checkServer.com.util;
public class CheckUtil {
// 测试用username,password
public static final String USERNAME = "user";
public static final String PASSWORD="123";
/**
* 校验用户名密码正确性
* @param username
* @param password
* @return
*/
public static boolean checkLogin(String username,String password){
if(username.equals(USERNAME) && password.equals(PASSWORD)){
return true;
}
return false;
}
/**
* 校验cookie正确性
* @param cookieName
* @param cookieValue
* @return
*/
public static boolean checkCookie(String cookieName,String cookieValue){
if(cookieName.equals("ssocookie") && cookieValue.equals("sso")){
return true;
}
return false;
}
}
Client1LoginController.java
package www.client1.com.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import www.client1.com.form.LoginForm;
import www.client1.com.util.Client1Util;
@Controller
@RequestMapping("/client1")
public class Client1LoginController {
@Autowired
HttpServletRequest request;
@Autowired
HttpServletResponse response;
/**
* 访问client1主页面方法
* @return
*/
@RequestMapping("/main")
public ModelAndView main(){
ModelAndView mv = new ModelAndView();
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (Cookie cookie : cookies) {
if(cookie.getName().equals("ssocookie")){
Map<String,String> map = new HashMap<String,String>();
map.put("cookieName", cookie.getName());
map.put("cookieValue", cookie.getValue());
String result = Client1Util.doGet("http://www.checkServer.com/sso-cross/server/checkCookie.do",map);
if(result.equals("1")){
mv.setViewName("success1");
return mv;
}
}
}
}
mv.setViewName("login");
mv.addObject("gotoUrl", "http://www.client1.com/sso-cross/client1/main.do");
mv.addObject("path", "client1");
return mv;
}
/**
* client1的登录方法
* @param form
* @return
*/
@RequestMapping("/doLogin")
public ModelAndView doLogin(LoginForm form){
ModelAndView mv = new ModelAndView();
Map<String,String> map = new HashMap<String,String>();
map.put("username", form.getUsername());
map.put("password", form.getPassword());
String result = Client1Util.doGet("http://www.checkServer.com/sso-cross/server/doLogin.do", map);
if(result.equals("1")){
List<String> hiddenUrl = new ArrayList<String>();
hiddenUrl.add("http://www.client1.com/sso-cross/client1/addCookie.do");
hiddenUrl.add("http://www.client2.com/sso-cross/client2/addCookie.do");
mv.addObject("hiddenUrl", hiddenUrl);
mv.setViewName("success1");
return mv;
}
mv.setViewName("login");
mv.addObject("gotoUrl", "http://www.client1.com/sso-cross/client1/main.do");
mv.addObject("path", "client1");
return mv;
}
/**
* client1添加cookie方法
*/
@ResponseBody
@RequestMapping("addCookie")
public void addCookie(){
Cookie cookie = new Cookie("ssocookie","sso");
cookie.setPath("/");
response.addCookie(cookie);
}
}
LoginForm.java
package www.client1.com.form;
public class LoginForm {
private String username;
private String password;
private String gotoUrl;
private String path;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGotoUrl() {
return gotoUrl;
}
public void setGotoUrl(String gotoUrl) {
this.gotoUrl = gotoUrl;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
Client1Util.java
package www.client1.com.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class Client1Util {
/**
* 向登录服务器通信,校验用户名密码或者cookie是否存在
* @param url
* @param map
* @return
*/
public static String doGet(String url, Map<String, String> map) {
StringBuffer sb = new StringBuffer();
HttpURLConnection httpURLConnection = null;
try {
StringBuffer t_s = new StringBuffer(url + "?");
for (Map.Entry<String, String> entry : map.entrySet()) {
t_s.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
url = t_s.substring(0, t_s.length() - 1);
URL urls = new URL(url);
httpURLConnection = (HttpURLConnection) urls.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.connect();
InputStream in = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String temp = null;
while ((temp = br.readLine()) != null) {
sb.append(temp);
}
br.close();
isr.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
return sb.toString();
}
}
Client2LoginController.java
package www.client2.com.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import www.client2.com.form.LoginForm;
import www.client2.com.util.Client2Util;
@Controller
@RequestMapping("/client2")
public class Client2LoginController {
@Autowired
HttpServletRequest request;
@Autowired
HttpServletResponse response;
/**
* 访问client2主页面方法
* @return
*/
@RequestMapping("/main")
public ModelAndView main(){
ModelAndView mv = new ModelAndView();
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (Cookie cookie : cookies) {
if(cookie.getName().equals("ssocookie")){
Map<String,String> map = new HashMap<String,String>();
map.put("cookieName", cookie.getName());
map.put("cookieValue", cookie.getValue());
String result = Client2Util.doGet("http://www.checkServer.com/sso-cross/server/checkCookie.do",map);
if(result.equals("1")){
mv.setViewName("success2");
return mv;
}
}
}
}
mv.setViewName("login");
mv.addObject("gotoUrl", "http://www.client2.com/sso-cross/client2/main.do");
mv.addObject("path", "client2");
return mv;
}
/**
* client2的登录方法
* @param form
* @return
*/
@RequestMapping("/doLogin")
public ModelAndView doLogin(LoginForm form){
ModelAndView mv = new ModelAndView();
Map<String,String> map = new HashMap<String,String>();
map.put("username", form.getUsername());
map.put("password", form.getPassword());
String result = Client2Util.doGet("http://www.checkServer.com/sso-cross/server/doLogin.do", map);
if(result.equals("1")){
List<String> hiddenUrl = new ArrayList<String>();
hiddenUrl.add("http://www.client1.com/sso-cross/client1/addCookie.do");
hiddenUrl.add("http://www.client2.com/sso-cross/client2/addCookie.do");
mv.addObject("hiddenUrl", hiddenUrl);
mv.setViewName("success2");
return mv;
}
mv.setViewName("login");
mv.addObject("gotoUrl", "http://www.client2.com/sso-cross/client2/main.do");
mv.addObject("path", "client2");
return mv;
}
/**
* client2添加cookie方法
*/
@ResponseBody
@RequestMapping("addCookie")
public void addCookie(){
Cookie cookie = new Cookie("ssocookie","sso");
cookie.setPath("/");
response.addCookie(cookie);
}
}
Client2Util.java
package www.client2.com.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class Client2Util {
/**
* 向登录服务器通信,校验用户名密码或者cookie是否存在
* @param url
* @param map
* @return
*/
public static String doGet(String url,Map<String,String> map){
StringBuffer sb = new StringBuffer();
HttpURLConnection httpURLConnection = null;
try{
StringBuffer t_s = new StringBuffer(url + "?");
for (Map.Entry<String,String> entry: map.entrySet()) {
t_s.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
url = t_s.substring(0,t_s.length()-1);
URL urls = new URL(url);
httpURLConnection = (HttpURLConnection) urls.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.connect();
InputStream in = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String temp = null;
while((temp = br.readLine()) != null){
sb.append(temp);
}
br.close();
isr.close();
in.close();
}catch(IOException e){
e.printStackTrace();
}finally{
if(httpURLConnection != null){
httpURLConnection.disconnect();
}
}
return sb.toString();
}
}
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
</beans>
springMVC.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="www.checkServer.com.controller"></context:component-scan>
<context:component-scan base-package="www.client1.com.controller"></context:component-scan>
<context:component-scan base-package="www.client2.com.controller"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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_3_0.xsd">
<!-- 配置Spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- mybatis的配置文件要写到这里不能写到springMVC下面,否则在动态扫描Bean的时候会出现找不到mybatis定义的mapper的情况 -->
<param-value>classpath*:spring.xml</param-value>
</context-param>
<!-- 配置Spring mvc -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+ path + "/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>登錄</title>
</head>
<body>
<center>
<h1>请登录</h1>
<form action="./${path}/doLogin.do" method="post">
<span>用户名:</span><input type="text" name="username" />
<span>密码</span><input type="password" name="password" />
<input type="submit" value="登录" />
<input type="hidden" name="gotoUrl" value="${gotoUrl}" />
</form>
</center>
</body>
</html>
success1.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 + "/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>client1登录成功</title>
</head>
<body>
<center>
<h1>client1登录成功</h1>
</center>
<c:forEach var="url" items="${hiddenUrl}">
<iframe src="${url}" width="0px" height="0px" ></iframe>
</c:forEach>
</body>
</html>
success2.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 + "/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>client2登录成功</title>
</head>
<body>
<center>
<h1>client2登录成功</h1>
</center>
<c:forEach var="url" items="${hiddenUrl}">
<iframe src="${url}" width="0px" height="0px" ></iframe>
</c:forEach>
</body>
</html>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>sso-cross</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.13.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.2</version>
</dependency>
</dependencies>
</project>
以上是手写部分。
当然sso的实现方法还有使用cas的方式。使用还是比较简单的,可以参照下面几篇文章。
https://www.cnblogs.com/ruiati/p/6265194.html
https://www.cnblogs.com/notDog/p/5275149.html
https://www.cnblogs.com/13jhzeng/p/5722153.html
如果想修改登录界面样式可以先将cas-server-webapp-3.5.2.1.war导入到eclipse,修改够打包发布即可。