SSO单点登陆

一、理论基础

1.1、为什么需要做单点登陆系统

大型互联网公司中,项目旗下可能会有多个子系统,每个登录实现统一管理,多个账户实现统一管理。

例子:比如阿里旗下支付宝,咸鱼等,只要有一个系统登录情况下,其他就不需要登录了(或者直接拿一个授权就行了)

XXL-SSO是国产的,CAS相对来说好点

1.2、单点登陆系统实现思路

核心:靠认证授权中心

1.3、单点登陆系统框架

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

xxl-sso官方文档:http://www.xuxueli.com/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

 

疑问1:为什么在认证授权中心登陆成功之后,会带一个xxl_sso_sessionid参数?

疑问2:为什么ssoClient需要集成redis?

疑问3:认证授权中心如何实现集群化?

疑问4:访问客户端的时候,如何自动重定向到认证授权中心的?

1.4、Client原理分析

原理:

  1. 先从Cookie中获取当前CookieId
  2. 如果用户没有登陆的情况下,重定向到认证授权中心
  3. 认证授权登陆成功之后,在认证授权域名下存放对应的cookie信息
  4. 认证授权系统回调到子系统中传递xxl_sso_sessionid
  5. http://xxlssoclient1.com:8084/xxl-sso-web-sample-springboot/?xxl_sso_sessionid=1000_4529db8531d54e23856e44002ace6cbb

  6. 回调到子系统的时候,进XxlSsoWebFilter拦截 获取xxl_sso_sessionid 信息
  7. 子系统使用xxl_sso_sessionid从redis查询认证授权系统登陆的用户信息,将用户信息在子系统域名下存放对应的用户Cookie信息

 

http://xxlssoserver.com:8080/xxl-sso-server/login?redirect_url=http://xxlssoclient1.com:8084/xxl-sso-web-sample-springboot/

疑问1:为什么redirect_url地址在认证授权中心登陆成功之后,返回原来地址 (回调地址)?

疑问2:其他其他子系统如何实现面密登陆的呢?

1.5、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;
        }      
    }

1.6、XXL-SSOToken认证

注意:基于token令牌模式的单点登录只适合移动端(客户端)不适合web系统(java)

注意:vue或者react(客户端技术)是通过token令牌模式实现单点登录

如何保证SSO-Server高可用的问题
可以考虑SSO-Servet集群问题
思考:SSOClient实现注销,URL地址如何拼接

SSO基于Cookie 形式 、Token形式 

SSO基于Token形式的实现  普通登陆一模一样的路程

基于令牌形式实现SSO

1.	调用认证授权中心接口登陆返回用户令牌信息
2.	SSOClient项目需要实现单点登陆的话,在调用SSOClient接口的时候请求头中传递Token信息
3.	sessionId 相当于Token

二、代码集成XXL-SSO开源项目

A.	认证授权中心xxl-sso-server
    修改登陆数据库验证
    修改页面静态资源
B.	SSOClient端整合

(1)创建认证授权中心shop-basics-xxl-sso-server

Maven依赖信息:
 

<!-- 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.mayikt</groupId>
			<artifactId>meite-shop-service-api-member</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>com.mayikt</groupId>
			<artifactId>meite-shop-common-web-core</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

(2)改造登陆代码

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";
		}

(3)登陆接口

@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);

(4)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-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/

单点登陆系统设计思想都是一样

联合登陆都会遵循oatuh2.0协议

 

思考1:我们在项目中,如何集成xxl-sso框架?

 肯定是修改xxl-sso框架?应该修改那些地方?

  1. 认证授权中心

需要介入微服务基础设施

修改登陆验证接口(调用会员数据库验证)

需要修改登陆界面

    2.SSOClient集成

   集成XxlSsoConfig使用XxlSsoWebFilter(注意排除请求)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值