版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shuaipu813/article/details/53259292
SSO单点登录(以下全是个人理解,如果有误,共同批评进步)
1.什么是单点登录:
在不同的应用中,受保护的同一用户,登录一次就可以访问相关的其他系统应用。比如搜狐登录后,可以直接访问博客、邮箱等等,而不用再重新登录博客系统、邮箱系统等等。方便了用户的操作。
2.同域下单点登录实现:
单点登录流程和大概思路如下:
我们用具体代码来实现以下操作:
我们有四个项目,app1、app2、ssofilter、ssoserver分别是web系统1、web系统2、拦截请求系统、sso认证中心。
app1系统结构如下:
就一个jsp文件,用来获取用户信息。app2系统的页面也一样。
我们先写sso认证中心的代码,这里只写主要的代码:
登录的代码,登录成功后写入cookie,将令牌和用户信息存入全局信息中
/**
* get请求,表示没有登录直接访问。获取路径,返回登录页面
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求路径
String backurl=request.getParameter("backurl");
request.setAttribute("backurl", backurl);
request.getRequestDispatcher("index.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决中文乱码
request.setCharacterEncoding("utf-8");
String username=request.getParameter("username");
String password=request.getParameter("password");
String backurl=request.getParameter("backurl");
try {
User user=new User();
//根据用户名名称查询用户
user = UserUtil.getUserByname(username);
if(null!=user&& password.equals(user.getPassword())){
System.out.println("登录成功!");
/*String[] uuid=UUID.randomUUID().toString().split("-");
StringBuffer token=new StringBuffer();
for (String string : uuid) {
token.append(string);
}*/
//生成令牌,根据java生成uuid,将其中的-符号替换为空字符串,然后转成小写字母
String token=UUID.randomUUID().toString().replace("-", "").toLowerCase();
//根据自定义的全局工具类,将令牌作为key,将用户信息作为value存入Map中
MapUtil.addToken(token, user);
//创建一个cookie
Cookie cookie=new Cookie("token", token);
cookie.setHttpOnly(true);
cookie.setPath("/");
//将cookie添入响应中,返回客户端
response.addCookie(cookie);
if(StringUtils.isNullOrEmpty(backurl)){
//如果没有获取到请求路径,表示用户直接访问login登录页面,这里可以将值设置为登录成功后的主页
backurl="success";
}else{
//将路径解码
backurl=URLDecoder.decode(backurl,"utf-8");
}
//重新定向到返回路径
//response.sendRedirect(backurl);
response.getWriter().println(backurl);
}else{
response.setContentType("text/html;utf-8");
response.setCharacterEncoding("utf-8");
System.out.println("用户名或密码不对!");
response.getWriter().println("用户名或密码不对");
}
} catch (SQLException e) {
e.printStackTrace();
}
SSO认证中心,验证代码:
//获取请求令牌
String token=request.getParameter("token");
//根据令牌去请求对应的用户信息
User user=MapUtil.getUserByToken(token);
//判断令牌是否有效
if(null!=user){
//有效,返回用户信息
response.getWriter().println("username="+URLEncoder.encode(user.getUsername(),"utf-8")+";password="+user.getPassword());
}else{
//无效,返回空字符串
response.getWriter().println("");
}
拦截请求系统代码:
//将ServletRequest和ServletResponse转为Http请求的
HttpServletRequest httprequest=(HttpServletRequest)request;
HttpServletResponse httpresponse=(HttpServletResponse)response;
//获取cookie数组
Cookie[] cookies=httprequest.getCookies();
String token=null;
if(null!=cookies && 0<cookies.length){
for (Cookie cookie : cookies) {
if(cookie.getName().equals("token")){
token=cookie.getValue();
}
}
}
//获取url路径,?之前
String url=httprequest.getRequestURI();
//获取?之后的路径
String queryurl=httprequest.getQueryString();
if(null!=queryurl){
url+="?"+queryurl;
}
if(null==token){
//令牌为空,直接返回登录页面,重新登录生成
httpresponse.sendRedirect(SSOLOGINURL+"?backurl="+URLEncoder.encode(url,"utf-8"));
}else{
//请求SSO服务端,验证令牌的有效性
URL urlconn=new URL(SSOVAILDATE+"?token="+token);
HttpURLConnection connection=(HttpURLConnection)urlconn.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Charset", "utf-8");
connection.connect();
InputStream input=connection.getInputStream();
byte[] by=new byte[1024];
input.read(by);
String stringbuffer=new String(by);
if(stringbuffer.length()>0){
String[] userdata=stringbuffer.split(";");
User user=new User();
for (String string : userdata) {
String[] string2=string.split("=");
switch (string2[0]){
case "username":
user.setUsername(URLDecoder.decode(string2[1],"utf-8"));
break;
case "password":
user.setPassword(string2[1]);
break;
}
}
request.setAttribute("user", user);
filter.doFilter(httprequest, httpresponse);
}else{
//标示token无效,将请求定向到登录地址
httpresponse.sendRedirect(SSOLOGINURL+"?backurl="+URLEncoder.encode(url,"utf-8"));
}
}
将
拦截请求系统打成jar包,加入web1和web2中使用,在web1和web2中配置拦截器
<filter>
<filter-name>loginfilter</filter-name>
<filter-class>com.client.ssoFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginfilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
还有SSO认证中心的登录页面:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>登录</title>
<script type="text/javascript">
function submitData(){
var httpRequest=createXMLHttpRequest();
httpRequest.onreadystatechange=function(){
if(httpRequest.readyState==4 && httpRequest.status==200){
if("用户名或密码不对".trim()==(httpRequest.responseText).trim()){
alert(httpRequest.responseText);
return false;
}else{
location.href=httpRequest.responseText;
}
}
};
var postdata="username="+document.getElementById("username").value+"&backurl="+document.getElementById("backurl").value+"&password="+document.getElementById("password").value;
/* var forms=new FormData();
forms.append("username", document.getElementById("username").value);
forms.append("backurl", document.getElementById("backurl").value);
forms.append("password", document.getElementById("password").value); */
httpRequest.open("post", document.getElementById("dataFrom").getAttribute("action"),true);
httpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
httpRequest.send(postdata);
}
function createXMLHttpRequest(){
var xmlHttp;
if(window.ActiveXObject)
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if(window.XMLHttpRequest)
{
xmlHttp = new XMLHttpRequest();
}
return xmlHttp;
}
</script>
</head>
<body>
<form action="login" method="post" id="dataFrom">
<table>
<tr>
<td><input type="hidden" name="backurl" id="backurl" value="${backurl}"/></td>
</tr>
<tr>
<td><input type="text" name="username" id="username"/></td>
</tr>
<tr>
<td><input type="password" name="password" id="password"/></td>
</tr>
<tr>
<td><input type="button" value="登录" onclick="submitData()"/> <input type="reset" value="重新输入"/></td>
</tr>
</table>
</form>
</body>
</html>