更新時間:2022-12-26 11:06:05 來源:動力節點 瀏覽1175次
通過上述圖形,我們可以看到SSO的大體實現步驟主要分為兩大步:存儲登錄信息,查驗登錄信息。
對于SSO,我們也可以將之分為兩大不同的類型:同域SSO和跨域SSO;其中同域SSO又可以分為完全同域SSO和同父域SSO。
其實現步驟主要分為:前期準備工作,編寫統一登錄接口,編寫登錄校驗接口,編寫驗證頁面,實現SSO;
編寫統一登錄接口:
登錄頁面的編寫主要是錄入用戶的登錄信息,包括用戶名,密碼,以及登錄頁面的地址。因為存在多個應用系統,所以用戶在統一登錄頁面登陸成功后,系統需要知道用戶想要訪問的是哪個系統頁面,這個時候就需要記錄用戶第一次訪問的地址,等到用戶登錄成功后,就可直接跳轉該頁面。
<body>
<center>
<h1>請登錄</h1>
<form action="/sso/doLogin.action" method="POST">
<span>用戶名:</span><input type="text" name="username" />
<span>密碼:</span><input type="text" name="password" />
//暫存需要登錄頁面的url地址
<input type="hidden" name="gotoUrl" value="${gotoUrl}" />
<input type="submit" />
</form>
</center>
</body>
登錄方法的編寫:需要新建cookie,將用戶的信息存進cookie中,并指定cookie的路徑,因為是完全同域,所以cookie的地址可以簡寫為(“/”)。這里必須要設置cookie的路徑,如果不設置,那么cookie的路徑將并不一定在當前域名的頂層,它有可能就在當前的這個路徑下才可見,這樣會導致在當前域的其他路徑下找不到這個cookie,解決辦法就是把cookie設置到當前域的最頂層域里面,這樣當前域下的所有應用就會都可見。
public String doLogin(){
//新建Cookie
Cookie cookie = new Cookie("ssocookie","sso");
//設置Cookie路徑
cookie.setPath("/");
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);
return "success";
}
登錄校驗接口的編寫:通常SSO登錄接口校驗都會放在登錄攔截器中,當用戶想要訪問某個系統時,登錄攔截器將直接重定向到統一登錄頁面,用戶填寫完登錄信息后,就會進行登錄校驗。
//cookie校驗(放在攔截器中進行校驗)
public static boolean checkCookie(HttpServletRequst request){
Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookies cookie:cookies){
if(cookie.getName().equals("ssocookie")
&&cookie.getValue().equals("sso")){
return true;
}
}
}
return false;
}
編寫測試主頁
public String main(){
HttpServletRequst request = ServletActionContext.getRequst();
if(SSOCheck.checkCookie(request)){
//登陸成功,記錄用戶登錄信息......
return "success";
}
//登錄失敗,暫存需要訪問的地址,登錄成功后,直接訪問該地址
gotoUrl="/demo1/main.action";
return "login";
}
最后還有struts2的配置文件
<struts>
<package name="sso" namespace="/sso" extends="struts-default">
<action name="doLogin" class="com.xm.controllerAction.SSOAction" method="doLogin">
<!-- 用戶登錄成功后,需要進行重定向,重新跳轉到用戶最初訪問的路徑 -->
<result name="success" type="redirect">${gotoUrl}</result>
</action>
</package>
<package name="demo1" namespace="/demo1" extends="struts-default">
<action name="main" class="com.xm.controllerAction.Demo1Action" method="main">
<result name="success">/success1.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
<package name="demo2" namespace="/demo2" extends="struts-default">
<action name="main" class="com.xm.controllerAction.Demo2Action" method="main">
<result name="success">/success2.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
</struts>
其實現步驟與上述完全同域SSO相同。
其中檢驗域名:http://check.x.com
測試頁面域名:http://demo1.x.com和http://demo2.x.com
編寫統一登錄接口:
代碼實現與完全同域名SSO基本一致,不過在設置提交路徑時,因為二級域名不同,所以不能寫成相對路徑,需要寫成絕對路徑地址。
<body>
<center>
<h1>請登錄</h1>
//表單提交地址需寫成絕對路徑,不能寫相對路徑
<form action="http://check.x.com/sso/doLogin.action" method="POST">
<span>用戶名:</span><input type="text" name="username" />
<span>密碼:</span><input type="text" name="password" />
//暫存需要登錄頁面的url地址
<input type="hidden" name="gotoUrl" value="${gotoUrl}" />
<input type="submit" />
</form>
</center>
</body>
登錄方法:在設置cookie路徑的時候有所變化,同上,為了使得當前兩個同父域的應用系統都可見這個cookie,那么我們需要將這個cookie設置到父域下面,而不應該設置到本域下面,這樣才可以實現域不同,但是父域相同的應用都可以看到的這個cookie。
public String doLogin(){
boolean ok = SSOCheck.checkLogin(userName,passWord);
if(ok){
//新建Cookie
Cookie cookie = new Cookie("ssocookie","sso");
//設置Cookie的父域
cookie.setDomain(".x.com");
//設置Cookie路徑
cookie.setPath("/");
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);
return "success";
}
}
登錄校驗接口:因為有著不同的域,所以我們應該將登錄所獲得cookie傳到專門的校驗域下的校驗方法中進行校驗,否則我們需要在各自不同的登錄頁面實現校驗,這樣顯得代碼十分的冗余。
private String cookieName;
private String cookieValue;
public String getCookieName() {
return cookieName;
}
public void setCookieName(String cookieName) {
this.cookieName = cookieName;
}
public String getCookieValue() {
return cookieValue;
}
public void setCookieValue(String cookieValue) {
this.cookieValue = cookieValue;
}
//二級域名向二級域名發送請求
public void checkCookie() throws IOException{
boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
String result="0";
if(ok){
result="1";
}
HttpServletResponse response = ServletActionContext.getResponse();
response.getWriter().print(result);
response.getWriter().close();
}
public static boolean checkCookie(String cookieName,String cookieValue){
if(cookieName.equals("ssocookie")&&cookieValue.equals("sso")){
return true;
}
return false;
}
編寫測試主頁
public String main(){
HttpServletRequst request = ServletActionContext.getRequst();
//獲取cookie
Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookie cookie:cookies){
if(cookie.getName().equals("ssocookie")){
//向檢驗服務器中發送cookieName和cookieValue
String result = Demo1Tool.doGet("http://check.x.com/so/checkCookie.action",
cookie.getName(),cookie.getValue());
if(result.equals("1")){
return "success";
}
}
}
}
//暫存需要訪問的地址,登錄成功后,直接訪問該地址
gotoUrl="http://demo1.x.com/demo1/main.action";
return "login";
}
public static String doGet(String url,String cookieName,String cookieValue){
//定義返回值
StringBuffer sb = new StringBuffer();
HttpURLConnection httpURLConnection = null;
try{
//校驗方法所在的地址
URL urls = new URL(url+
"?cookieName="+cookieName+"&cookieValue="+cookieValue);
//打開連接
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();
}
struts配置文件
<struts>
<package name="sso" namespace="/sso" extends="struts-default">
<action name="doLogin" class="com.xm.controllerAction.SSOAction" method="doLogin">
<result name="success" type="redirect">${gotoUrl}</result>
</action>
<action name="checkCookie" class="check.x.com.SSOAction" method="checkCookie">
</action>
</package>
<package name="demo1" namespace="/demo1" extends="struts-default">
<action name="main" class="demo1.x.com.Demo1Action" method="main">
<result name="success">/success1.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
<package name="demo2" namespace="/demo2" extends="struts-default">
<action name="main" class="demo2.x.com.Demo2Action" method="main">
<result name="success">/success2.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
</struts>
其實現步驟與完全同域SSO相同。
其中檢驗域名:http://www.x.com
測試頁面域名:http://www.a.com和http://www.b.com
編寫統一登錄接口:
<body>
<center>
<h1>請登錄</h1>
//這里需要向當前所在的域提交申請,因為如果向校驗域提交申請,那么在本域中將無法看到cookie
<form action="/${path}/doLogin.action" method="POST">
<span>用戶名:</span><input type="text" name="username" />
<span>密碼:</span><input type="text" name="password" />
//暫存需要登錄頁面的url地址
<input type="hidden" name="gotoUrl" value="${gotoUrl}" />
<input type="submit" />
</form>
</center>
</body>
登錄方法:
public String doLogin(){
Map<String,String> map = new HashMap<String,String>();
map.put("userName", userName);
map.put("password", passWord);
String result = Demo1Tool.doGet("http://www.x.com/sso/doLogin.action",map);
if(result.equals("1")){
return "success";
}
return "login";
}
public void doLogin() throw IOException{
boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
String result = "0";
if(ok){
result = "1";
}
HttpServletResponse response = ServletActionContext.getResponse();
response.getWriter().print(result);
response.getWriter().close();
}
登錄校驗接口;和同父域SSO的登錄校驗基本一致,沒有什么變化。
public void checkCookie() throws IOException{
boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
String result="0";
if(ok){
result="1";
}
HttpServletResponse response = ServletActionContext.getResponse();
response.getWriter().print(result);
response.getWriter().close();
}
編寫測試主頁
public String main(){
HttpServletRequst request = ServletActionContext.getRequst();
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("userName", cookie.getName());
map.put("password", cookie.getValue());
String result = Demo1Tool.doGet("http://www.x.com/so/checkCookie.action",
cookie.getName(),cookie.getValue());
if(result.equals("1")){
return "success";
}
}
}
}
//暫存需要訪問的地址,登錄成功后,直接訪問該地址
path = "demo1";
gotoUrl="http://www.a.com/demo1/main.action";
return "login";
}
public static String doGet(String url,Map<String,String> map){
//定義返回值
StringBuffer sb = new StringBuffer();
HttpURLConnection httpURLConnection = null;
try{
StringBuffer t_s = new StringBuffer(url).append("?");
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();
}
至此,準備工作做完,接下來是跨域SSO實現中最重要的部分,也就是cookie的設置,在之前完全同域和同父域的情況下,為了實現SSO,我們在進行doLogin時就設置了cookie,因為域名相同,所以十分簡單,但是在跨域SSO中,因為不同域之間的cookie是不可見的,所以我們不可能只設置一個cookie,然后令所有的域名下的應用程序皆可見,所以我們應該在每個域下面都有著為本域設置cookie的方法,而不應該直接將設置cookie交給校驗域。
//為本域設置cookie的方法
public void addCookie(){
Cookie cookie = new Cookie("ssocookie","sso");
cookie.setPath("/");
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);
}
還需要在配置文件中進行配置:
<action name="addCookie" class="www.a.com.Demo1Action" method="addCookie"></action>
寫完好方法,則需要進行調用,因此我們需要找一個可以讓二者進行交會的地方,在這里我選擇了登錄成功的瞬間,通過隱藏的Iframe讓二者進行交會。
public String doLogin(){
Map<String,String> map = new HashMap<String,String>();
map.put("userName", userName);
map.put("password", passWord);
String result = Demo1Tool.doGet("http://www.x.com/sso/doLogin.action",map);
if(result.equals("1")){
return "success";
}
List hidderUrl = new ArrayList<String>();
hidderUrl.add("http://www.a.com/demo1/addCookie.action");
hidderUrl.add("http://www.b.com/demo2/addCookie.action");
return "login";
}
<c:forEach var="url" item="${hiddenUrl}">
<iframe src="${url}" width="0px" heigth="0px" style="display:none"></iframe>
</c:forEach>
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習