.

為什麼需要做單點登陸系統

大型網際網路公司中,公司旗下可能會有多個子系統,每個登陸實現統一管理
多個賬戶資訊統一管理 SSO單點登陸認證授權系統

總體設計架構圖

單點登陸系統實現思路

單點登陸系統框架官方網址

https://github.com/xuxueli/xxl-sso  xxl-sso

http://www.xuxueli.com/xxl-sso/#/ xxl-sso官方文件

思考需要修改XXL-SSO框架的幾點

1.	修改XXL-SSO認證服務授權頁面樣式
2.	修改XXL-SSO認證服務資料庫賬號密碼

http://xxlssoclient1.com:8084/xxl-sso-web-sample-springboot/

http://xxlssoclient2.com:8085/xxl-sso-web-sample-springboot/

客戶端訪問http://xxlssoclient1.com:8084重定向http://xxlssoserver.com:8080(SSO認證授權系統)

登陸成功之後跳轉原來地址:

http://xxlssoclient1.com:8084/xxl-sso-web-sample-springboot/?xxl_sso_sessionid=1000_1db53a90152140c6a8421c83546f75ab

疑問:為什麼在認證授權中心登陸成功之後,會帶一個xxl_sso_sessionid引數。
疑問:為什麼ssoClient需要整合redis
原始碼分析:

思考問題:
訪問客戶端的時候,如何自動重定向到認證授權中心的?

過濾器請求,如果沒有獲取到使用者的會話資訊的話,自動重定向跳轉到認證授權中心

重點斷點除錯 核心依賴Jar中 XxlSsoWebFilter類
Client原理分析:

1.	先從Cookie中獲取當前CookieId
2.	如果使用者沒有登陸的情況下,重定向到認證授權中心

http://xxlssoserver.com:8080/xxl-sso-server/login?redirect_url=http://xxlssoclient1.com:8084/xxl-sso-web-sample-springboot/
為什麼redirect_url地址
在認證授權中心登陸成功之後,返回原來地址 (回撥地址)

3.	認證授權登陸成功之後,在認證授權域名下存放對應的cookie資訊
4. 認證授權系統回撥到子系統中傳遞xxl_sso_sessionid
http://xxlssoclient1.com:8084/xxl-sso-web-sample-springboot/?xxl_sso_sessionid=1000_4529db8531d54e23856e44002ace6cbb

4.	回撥到子系統的時候,進XxlSsoWebFilter攔截 獲取xxl_sso_sessionid 資訊
5.	子系統使用xxl_sso_sessionid從redis查詢認證授權系統登陸的使用者資訊,將使用者資訊在子系統域名下存放對應的使用者Cookie資訊
這樣的 可以保證 認證授權系統和子系統雙方Cookie資訊同步

專案如何整合XXL-SSO專案

A.	認證授權中心xxl-sso-server
1.	修改登陸資料庫驗證
2.	修改頁面靜態資源
B.	SSOClient端整合

建立認證授權中心meite-shop-basics-xxl-sso-server

	<!-- freemarker -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>
		<!-- sso core -->
		<dependency>
			<groupId>com.xuxueli</groupId>
			<artifactId>xxl-sso-core</artifactId>
			<version>1.1.1-SNAPSHOT</version>
		</dependency>
		<!-- springcloud feign元件 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<dependency>
			<groupId>com.xuyu</groupId>
			<artifactId>xuyu-shop-service-api-member</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>com.xuyu</groupId>
			<artifactId>xuyu-shop-common-web-core</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

改造登陸程式碼

userLoginInpDTO.setMobile(username);
		userLoginInpDTO.setPassword(password);
		userLoginInpDTO.setLoginType(Constants.MEMBER_LOGIN_TYPE_PC);
		String info = webBrowserInfo(request);
		userLoginInpDTO.setDeviceInfor(info);
		BaseResponse<UserOutDTO> ssoLogin = memberServiceFeign.ssoLogin(userLoginInpDTO);
		if (!isSuccess(ssoLogin)) {
			redirectAttributes.addAttribute("errorMsg", ssoLogin.getMsg());
			redirectAttributes.addAttribute(Conf.REDIRECT_URL, request.getParameter(Conf.REDIRECT_URL));
			return "redirect:/login";
		}
		UserOutDTO data = ssoLogin.getData();
		if (data == null) {
			redirectAttributes.addAttribute("errorMsg", "使用者資訊資料為空!");
			redirectAttributes.addAttribute(Conf.REDIRECT_URL, request.getParameter(Conf.REDIRECT_URL));
			return "redirect:/login";
		}

登陸介面

@Override
	public BaseResponse<UserOutDTO> ssoLogin(@RequestBody UserLoginInpDTO userLoginInpDTO) {
		// 1.驗證引數
		String mobile = userLoginInpDTO.getMobile();
		if (StringUtils.isEmpty(mobile)) {
			return setResultError("手機號碼不能為空!");
		}
		String password = userLoginInpDTO.getPassword();
		if (StringUtils.isEmpty(password)) {
			return setResultError("密碼不能為空!");
		}
		// 判斷登陸型別
		String loginType = userLoginInpDTO.getLoginType();
		if (StringUtils.isEmpty(loginType)) {
			return setResultError("登陸型別不能為空!");
		}
		// 目的是限制範圍
		if (!(loginType.equals(Constants.MEMBER_LOGIN_TYPE_ANDROID) || loginType.equals(Constants.MEMBER_LOGIN_TYPE_IOS)
				|| loginType.equals(Constants.MEMBER_LOGIN_TYPE_PC))) {
			return setResultError("登陸型別出現錯誤!");
		}

		// 裝置資訊
		String deviceInfor = userLoginInpDTO.getDeviceInfor();
		if (StringUtils.isEmpty(deviceInfor)) {
			return setResultError("裝置資訊不能為空!");
		}
		// 2.對登陸密碼實現加密
		String newPassWord = MD5Util.MD5(password);
		// 3.使用手機號碼+密碼查詢資料庫 ,判斷使用者是否存在
		UserDo userDo = userMapper.login(mobile, newPassWord);
		if (userDo == null) {
			return setResultError("使用者名稱稱或者密碼錯誤!");
		}
		return setResultSuccess(MeiteBeanUtils.doToDto(userDo, UserOutDTO.class));
	}
	/**
	 * SSO認證系統登陸介面
	 * 
	 * @param userLoginInpDTO
	 * @return
	 */
	@PostMapping("/ssoLogin")
	public BaseResponse<UserOutDTO> ssoLogin(@RequestBody UserLoginInpDTO userLoginInpDTO);

shop-portal專案整合

application.yml

#### 整合freemarker
spring:
    freemarker:
        cache: false
        charset: UTF-8
        check-template-location: true
        content-type: text/html
        expose-request-attributes: true
        expose-session-attributes: true
        request-context-attribute: request
        suffix: .ftl
        template-loader-path:
        - classpath:/templates
    application:
        name: app-xuyu-portal-pay
###服務註冊到eureka地址
eureka:
  client:
    service-url:
           defaultZone: http://localhost:8100/eureka
server:
  port: 8050
redis:
 hostname: 127.0.0.1
 port: 6379
 password: 123456

xxl-sso:
  excluded:
    paths: 
xxl:
  sso:
    server: http://xxlssoserver.com:8080/xxl-sso-server
    logout:
      path: /logout
    redis:
      address: redis://127.0.0.1:6379

XxlSsoConfig

@Configuration
public class XxlSsoConfig implements DisposableBean {

	@Value("${xxl.sso.server}")
	private String xxlSsoServer;

	@Value("${xxl.sso.logout.path}")
	private String xxlSsoLogoutPath;

	@Value("${xxl-sso.excluded.paths}")
	private String xxlSsoExcludedPaths;

	@Value("${xxl.sso.redis.address}")
	private String xxlSsoRedisAddress;

	@Bean
	public FilterRegistrationBean xxlSsoFilterRegistration() {

		// xxl-sso, redis init
		JedisUtil.init(xxlSsoRedisAddress);

		// xxl-sso, filter init
		FilterRegistrationBean registration = new FilterRegistrationBean();

		registration.setName("XxlSsoWebFilter");
		registration.setOrder(1);
		registration.addUrlPatterns("/*");
		registration.setFilter(new XxlSsoWebFilter());
		registration.addInitParameter(Conf.SSO_SERVER, xxlSsoServer);
		registration.addInitParameter(Conf.SSO_LOGOUT_PATH, xxlSsoLogoutPath);
		registration.addInitParameter(Conf.SSO_EXCLUDED_PATHS, xxlSsoExcludedPaths);

		return registration;
	}

	@Override
	public void destroy() throws Exception {

		// xxl-sso, redis close
		JedisUtil.close();
	}
}

線上properties轉yml方式

https://www.bejson.com/devtools/properties2yaml/

host檔案配置域名

127.0.0.1 pay.xuyu.com:8050 支付專案
127.0.0.1 www.xuyu.com 入口網站

單點登陸系統設計思想都是一樣

聯合登陸都會遵循oatuh2.0協議

思考:我們在專案中,如何整合xxl-sso框架?

肯定是修改xxl-sso框架?應該修改那些地方?
1.	認證授權中心
需要介入微服務基礎設施
修改登陸驗證介面(呼叫會員資料庫驗證)
需要修改登陸介面
2.	SSOClient整合
   整合XxlSsoConfig使用XxlSsoWebFilter(注意排除請求)


portal-web 會員登陸、註冊 商品搜尋、下單
pay-web 單獨 聚合支付  銀聯 支付寶 微信支付

portal-web pay-web 需要實現SSO單點登陸

 XXL-SSO退出原始碼分析

http://www.xuxueli.com/xxl-sso/#/?id=%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E-1

XXL-SSO認證授權中心如何實現高可用

使用Nginx實現xxl-sso-server認叢集和故障轉移


    upstream  backServer{
	    server 127.0.0.1:8080;
	    server 127.0.0.1:8081;
	}
    server {
        listen       80;
        server_name  xxlssoserver.com;
        location / {
           proxy_pass http://backServer;
		    ###nginx與上游伺服器(真實訪問的伺服器)超時時間 後端伺服器連線的超時時間_發起握手等候響應超時時間
			proxy_connect_timeout 1s;
			###nginx傳送給上游伺服器(真實訪問的伺服器)超時時間
            proxy_send_timeout 1s;
			### nginx接受上游伺服器(真實訪問的伺服器)超時時間
            proxy_read_timeout 1s;
            index  index.html index.htm;
        }      
    }

XXL-SSOToken認證

1.如何保證SSO-Server高可用的問題
2.可以考慮SSO-Servet叢集問題

思考:SSOClient實現登出,URL地址如何拼接
1.SSO基於Cookie 形式 、Token形式 
2.SSO基於Token形式的實現  普通登陸一模一樣的路程

基於令牌形式實現SSO

1.	呼叫認證授權中心介面登陸返回使用者令牌資訊
2.	SSOClient專案需要實現單點登陸的話,在呼叫SSOClient介面的時候請求頭中傳遞Token資訊
3.	sessionId 相當於Token