SSO單點登入,簡單模擬
阿新 • • 發佈:2018-10-31
SSO單點登入(以下全是個人理解,如果有誤,共同批評進步)
1.什麼是單點登入:
在不同的應用中,受保護的同一使用者,登入一次就可以訪問相關的其他系統應用。比如搜狐登入後,可以直接訪問部落格、郵箱等等,而不用再重新登入部落格系統、郵箱系統等等。方便了使用者的操作。
2.同域下單點登入實現:
單點登入流程和大概思路如下:
我們用具體程式碼來實現以下操作:
我們有四個專案,app1、app2、ssofilter、ssoserver分別是web系統1、web系統2、攔截請求系統、sso認證中心。
app1系統結構如下:
就一個jsp檔案,用來獲取使用者資訊。app2系統的頁面也一樣。
我們先寫sso認證中心的程式碼,這裡只寫主要的程式碼:
登入的程式碼,登入成功後寫入cookie,將令牌和使用者資訊存入全域性資訊中
SSO認證中心,驗證程式碼:/** * 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(); }
攔截請求系統程式碼://獲取請求令牌 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>