1. 程式人生 > >SSO 單點登入 的筆記

SSO 單點登入 的筆記

1  系統中的事務問題

1.1  Spring預設的事務策略

1.1.1    關於程式碼中的try-catch

說明:

由於程式碼中採用spring的宣告式的事務處理,所有程式設計師我需關注事務控制,統統交給spring管理.

Spring要求,如果出現了執行時異常,spring才會回滾事務.

如果在程式碼中對入庫操作添加了try-catch ,則spring容器不能接收異常資訊,所以不會回滾事務.

 總結:tyr-catch不要加到入庫和更新操作上.儘量控制其範圍.

2  單點登入

2.1  單點登入介紹

2.1.1    什麼是單點登入

說明:使用者一次登入後,可以免密登入其相關係統

2.1.2    SSO分析

說明:

當用戶登陸QQ遊戲時 ,進行了登陸操作,當訪問QQ郵箱時,需要再次登入,因為Session沒有共享,是不同的物件.所以資料不能公用.

2.1.3    單點登入設計圖

 

2.1.4    單點登入說明:

 

1.當用戶第一次登陸時,先通過SSO單點登入系統進行登入操作.

 

2.根據使用者資訊查詢使用者資料驗證登入是否有效

3.如果使用者名稱和密碼都正確,則生成ticket.並將User物件轉化JSON資料

4.將ticket和UserJSON資料寫入redis快取中

5.當用戶登陸成功後,在cookie儲存ticket資訊.

6.當用戶再次訪問前臺系統時,首先根據ticke資訊,查詢redis快取伺服器.獲取使用者資料.

7.當用戶訪問購物車時,首先前臺會校驗,根據ticket查詢使用者資訊,如果使用者沒有登陸則轉向單點登入系統.

8.當用戶訪問訂單系統時,首先前臺會校驗,根據ticket查詢使用者資訊,如果沒有該使用者資訊,則轉向單點登入系統.

2.2  構建SSO單點登入伺服器

2.2.1    SSO專案說明

單點登入伺服器.需要操作資料庫,所以構建時需要Controller.Service.Mapper一同完成.

構建web專案.

2.2.2    構建web專案

選擇web骨架建立專案

引入jt-parentjar包

 

引入common

 

2.2.3    匯入tomcat外掛

<build>

      <plugins>

         <plugin>

            <groupId>org.apache.tomcat.maven</groupId>

            <artifactId>tomcat7-maven-plugin</artifactId>

            <version>2.2</version>

            <configuration>

                <port>8093</port>

                <path>/</path>

            </configuration>

         </plugin>

      </plugins>

   </build>

 

      

為sso新增啟動項

2.2.4    修改Nginx實現轉向

說明:通過nginx實現sso.jt.com的轉發

#京淘專案單點登入

   server {

      listen80;

      server_namesso.jt.com;

      location/ {

         proxy_passhttp://127.0.0.1:8093;

      }

   }

Nginx修改完成之後 重啟nginx

nginx -s reload

 

2.2.5    修改HOST檔案

新增host檔案.保證訪問sso.jt.com訪問本機地址.

 

2.3  匯入配置檔案

2.3.1    拷貝jt-manage的配置檔案

 

2.3.2    修改springMVC.xml

 

2.3.3    修改Spring的配置檔案

2.3.4    修改Mybatis配置檔案

修改pojo的包路徑 和mapper的包路徑

 

2.3.5    修改web.xml配置檔案

拷貝:manage.jt.com的web.xml配置檔案.到jt-sso單點登入中.

<?xml version="1.0"encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns="http://java.sun.com/xml/ns/javaee"

   xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

   id="jt-manage"version="2.5">

   <display-name>jt-sso</display-name>

  

   <!--配置監聽器啟動spring容器  -->

   <listener>

      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

   </listener>

   <context-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>classpath:/spring/applicationContext*.xml</param-value>

   </context-param>

  

    

   <!--1.配置前端控制器  -->

   <servlet>

      <servlet-name>springmvc</servlet-name>

      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

      <!--配置載入SpringMVC.xml -->

      <init-param>

         <param-name>contextConfigLocation</param-name>

         <param-value>classpath:/spring/springmvc.xml</param-value>

      </init-param>

   </servlet>

   <!--

      / 規定

      1.表示攔截全部的請求 

      2.攔截所有靜態資源js/css/image 後期配置放行

       3.放行.jsp資源

   -->

   <servlet-mapping>

      <servlet-name>springmvc</servlet-name>

      <url-pattern>/</url-pattern>

   </servlet-mapping>

  

  

   <!--配置全站亂碼解決 POST亂碼  -->

   <filter>

      <filter-name>characterEncoding</filter-name>

      <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

      <init-param>

         <!--定義預設字符集utf-8  -->

         <param-name>encoding</param-name>

         <param-value>UTF-8</param-value>

      </init-param>

   </filter>

  

   <filter-mapping>

      <filter-name>characterEncoding</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

</web-app>

3  登入業務邏輯

3.1  京淘前臺登入跳轉

3.1.1    登入/註冊的跳轉

@Controller

@RequestMapping("/user")

publicclass UserController {

  

   ///user/register.html實現登入和註冊頁面跳轉

   ///user/login.html

   @RequestMapping("/{param}")

   public String module(@PathVariable String param){

     

      //轉向使用者登陸和註冊頁面

      returnparam;

   }

 

}

 

4  使用者註冊的校驗

4.1  頁面JS分析

4.1.1    JS查詢

 

說明:

url:http://sso.jt.com/user/check/admin123/1?r=0.26835501213441115&callback=jsonp1517465570159&_=1517465578846

 

 

說明:

    頁面中通過JSONP的形式直接訪問SSO單點登入系統,校驗使用者名稱/密碼是否存在

4.2  SSO程式碼編輯

4.2.1    介面文件

請求方法

GET

URL

http://sso.jt.com/user/check/{param}/{type}

引數

格式如:chenchen/1

其中chenchen是校驗的資料

Type為型別,可選引數1 username2 phone3 email

示例

http://sso.jt.com/user/check/chenchen/1

返回值

{

status: 200  //200 成功,201 沒有查到

msg: “OK”  //返回資訊訊息

data: false  //返回資料true使用者已存在,false使用者不存在,可以

}

 

 

 

4.2.2    編輯POJO物件

@Table(name = "tb_user")

public class User extends BasePojo{

  

   @Id //表示主鍵資訊

   @GeneratedValue(strategy=GenerationType.IDENTITY) //主鍵自增

   private Long id;   //使用者的Id

   private String username; //使用者名稱

   private String password; //密碼   採用MD5加密

   private String phone;    //電話

   private String email;    //郵箱

4.2.3    編輯Mapper介面

 

public interface UserMapper extends SysMapper<User>{

  

   //查詢資料是否存在  將資料封裝為Map

   int findCheckUser(@Param("param")String param,@Param("cloumn")Stringcloumn);

 

}

 

在mybatis檔案中編輯userMapper.xml對映檔案

<?xml version="1.0"encoding="UTF-8"?>

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jt.sso.mapper.UserMapper">

  

   <!--使用#號獲取資料的值,一般建議使用,因為有預編譯的效用.

      $符使用時,只會出現在以列名為引數的應用.

      能用#號不用$

     

      如果在列名的欄位中使用#{}取值,相當於

      SELECT COUNT(*) FROM tb_user WHERE "username"= 'admin123'

     -->

   <select id="findCheckUser"resultType="int">

      select count(*) from tb_user where ${cloumn}= #{param}

   </select>

  

  

  

</mapper>

4.2.4    建立service介面和實現類

publicinterface UserService {

   //校驗資料是否存在

   Boolean findCheckUser(String param,Integer type);

 

}

4.2.5    編輯Service實現類

@Service

publicclass UserServiceImpl implementsUserService {

  

   @Autowired

   private UserMapper userMapper;

  

  

   //Type為型別,可選引數1 username2 phone3 email

   //SELECT COUNT(*)FROM tb_user WHERE username= 'admin123'

   @Override

   public Boolean findCheckUser(String param, Integer type) {

     

      String cloumn = null;

      switch (type) {

         case 1: cloumn = "username"; break;

         case 2: cloumn = "phone"; break;

         case 3: cloumn = "email"; break;

      }

      //1,0

      intcount = userMapper.findCheckUser(param,cloumn); 

      returncount ==1 ? true : false;

  

}

 

4.2.6    編輯Controller

//校驗使用者的註冊資訊

   //url:http://sso.jt.com/user/check/admin123/1?callback=jsonp1517465570159&_=1517465578846

   //1 username、2 phone、3 email

   @RequestMapping("/check/{param}/{type}")

   @ResponseBody

   public Object checkUser(@PathVariableString param,@PathVariable Integer type,String callback){

      try {

         //根據傳遞的引數判斷資料是否存在

         Boolean result = userService.findCheckUser(param,type);

         //返回JSONP的資料

         MappingJacksonValue jacksonValue=

                new MappingJacksonValue(SysResult.oK(result));

         jacksonValue.setJsonpFunction(callback);

         returnjacksonValue;

        

      } catch (Exception e) {

         e.printStackTrace();

         returnnull;

     

   }

 

4.3  使用者的註冊

4.3.1    JS請求

http://www.jt.com/service/user/doRegister

 

 

 

4.4  使用者的登陸

4.4.1    登陸的思路

1.當用戶點選登陸操作時,跳轉到登陸頁面

2.使用者輸入使用者名稱和密碼後點擊登陸按鈕發出請求.進行登入操作.

3.瀏覽器發出請求:

http://www.jt.com/service/user/doLogin?r=0.582247581950398

4.根據url接收使用者名稱和密碼資料

5.再次校驗使用者名稱和密碼是否為空

6.轉向登入頁面(js中已將實現)

7.如果使用者名稱和密碼都不為null,則呼叫

8.UserService 通過httpClient方式傳送資料

9.如果獲取的ticket不為null.則表示登入操作成功.如果ticket為null,直接返回null.

將ticket資訊寫入到Cookie中

4.5  實現前臺的登陸操作

4.5.1    頁面分析JS

JS:http://www.jt.com/service/user/doLogin?r=0.582247581950398

 

 

 

4.5.2    編輯UserController

//使用者登陸 http://www.jt.com/service/user/doLogin?r=0.582247581950398

   //通過login.jsp檢測登陸的username和password是否正確

   @RequestMapping("/doLogin")

   @ResponseBody

   public SysResult doLogin(String username,String password,

         HttpServletRequest request,HttpServletResponseresponse){

      //判斷使用者名稱和密碼是否為null

      if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){

         return SysResult.build(201, "使用者名稱密碼不能為空");

      }

      //當前輸入的使用者名稱是正確的

      try {

         //獲取使用者的ticket

         String ticket =

                userService.findUserByUP(username,password);

         //ticket不為空

         if(!StringUtils.isEmpty(ticket)){

            //如果ticket資料不為空 則寫入cookie

            //Cookie[] cookies = request.getCookies();

            //Cookie的名稱必須為 JT_TICKET

         CookieUtils.setCookie(request, response, "JT_TICKET", ticket);

            return SysResult.oK(ticket);

         }

      } catch (Exception e) {

         e.printStackTrace();

      }

     

      return SysResult.build(201, "使用者登陸失敗");

   }

4.5.3    編輯UserService

 

@Override

   public String findUserByUP(String username, String password) {

      String uri = "http://sso.jt.com/user/login";

      Map<String, String> map = new HashMap<String,String>();

      //注意不要有空格

      map.put("username", username);

      map.put("password", password);

      try {

         String resutJSON = httpClient.doPost(uri,map);

        

         //判斷資料是否有效  將其轉化為Sysresult物件

         SysResult sysResult =

         objectMapper.readValue(resutJSON,SysResult.class);

         //判斷SSO返回是否正確

         if(sysResult.getStatus() == 200){

            return (String) sysResult.getData();

         }

        

      } catch (Exception e) {

         e.printStackTrace();

      }

      returnnull;

   }

5  作業:

1.  試著完成使用者登陸操作.

2.  試寫使用者登陸回顯操作

說明:當用戶登陸成功後,頁面會發出請求.根據ticket從redis中查詢使用者資訊

請求路徑:http://sso.jt.com/user/query/ticket資訊

 

    根據業務介面檔案,查詢使用者資訊.

最終實現效用: