目前每家企业或者平台都存在不止一套系统,由于历史原因每套系统采购于不同厂商,所以系统间都是相互独立的,都有自己的用户鉴权认证体系,当用户进行登录系统时,不得不记住每套系统的用户名密码,同时,管理员也需要为同一个用户设置多套系统登录账号,这对系统的使用者来说显然是不方便的。我们期望的是如果存在多个系统,只需要登录一次就可以访问多个系统,只需要在其中一个系统执行注销登录操作,则所有的系统都注销登录,无需重复操作,这就是单点登录(Single Sign On 简称SSO)系统实现的功能。,单点登录是系统功能的定义,而实现单点登录功能,目前开源且流行的有CAS和OAuth2两种方式,过去我们用的最多的是CAS,现在随着SpringCloud的流行,更多人选择使用SpringSecurity提供的OAuth2认证授权服务器实现单点登录功能。,OAuth2是一种授权协议的标准,任何人都可以基于这个标准开发Oauth2授权服务器,现在百度开放平台、腾讯开放平台等大部分的开放平台都是基于OAuth2协议实现, OAuth2.0定义了四种授权类型,最新版OAuth2.1协议定义了七种授权类型,其中有两种因安全问题已不再建议使用:,通过SpringSecurity官网可知,通过长期的对OAuth2的支持,以及对实际业务的情景考虑,大多数的系统都不需要授权服务器,所以,Spring官方不再推荐使用spring-security-oauth2,SpringSecurity逐渐将spring-security-oauth2中的OAuth2登录、客户端、资源服务器等功能抽取出来,集成在SpringSecurity中,并单独新建spring-authorization-server项目实现授权服务器功能。,目前我们了解最多的是Spring Security OAuth对OAuth2协议的实现和支持,这里需要区分Spring Security OAuth和Spring Security是两个项目,过去OAth2相关功能都在Spring Security OAuth项目中实现,但是自SpringSecurity5.X开始,SpringSecurity项目开始逐渐增加Spring Security OAuth中的功能,自SpringSecurity5.2开始,添加了OAuth 2.0 登录, 客户端, 资源服务器的功能。但授权服务器的功能,并不打算集成在SpringSecurity项目中,而是新建了spring-authorization-server项目作为单独的授权服务器:详细介绍。spring-security实现的是OAuth2.1协议,spring-security-oauth2实现的是OAuth2.0协议。,Spring未来的计划是将 Spring Security OAuth 中当前的所有功能构建到 Spring Security 5.x 中。 在 Spring Security 达到与 Spring Security OAuth 的功能对等之后,他们将继续支持错误和安全修复至少一年。,因spring-authorization-server目前最新发布版本0.2.3,部分功能仍在不断地修复和完善,还不足以应用到实际生产环境中,所以,我们目前使用spring-security-oauth2作为授权服务器,待后续spring-authorization-server发布稳定版本后,再进行迁移升级。,在GitEgg微服务框架中,gitegg-oauth已经引入了spring-security-oauth2,代码中使用了了Oauth2的密码授权和刷新令牌授权,并且自定义扩展了【短信验证码授权类型】和【图形验证码授权】,这其实是密码授权的扩展授权类型。,目前,基本上所有的SpringCloud微服务授权方式都是使用的OAuth2密码授权模式获取token,可能你会有疑惑,为什么上面最新的Oauth2协议已经不建议甚至是禁止使用密码授权类型了,而我们GitEgg框架的系统管理界面还要使用密码授权模式来获取token?因为不建议使用密码授权类型的原因是第三方客户端会收集用户名密码,存在安全风险。而在我们这里,我们的客户端是自有系统管理界面,不是第三方客户端,所有的用户名密码都是我们自有系统的用户名密码,只要做好系统安全防护,就可最大限度的避免用户名密码泄露给第三方的风险。,在使用spring-security-oauth2实现单点登录之前,首先我们一定要搞清楚单点登录SSO、OAuth2、spring-security-oauth2的区别和联系:,单点登录业务流程时序图:,1、用户通过浏览器访问A系统被保护的资源链接。,2、A系统判断当前会话是否登录,如果没有登录则跳转到A系统登录地址/login。,3、A系统首次接收到/login请求时没有state和code参数,此时A系统拼接系统配置的单点登录服务器授权url,并重定向至授权链接。,4、单点登录服务器判断此会话是否登录,如果没有登录,那么返回单点登录服务器的登录页面。,5、用户在登录页面填写用户名、密码等信息执行登录操作。,6、单点登录服务器校验用户名、密码并将登录信息设置到上下文会话中。,7、单点登录服务器重定向到A系统的/login链接,此时链接带有code和state参数。,8、A系统再次接收到/login请求,此请求携带state和code参数,系统A通过OAuth2RestTemplate请求单点登录服务端/oauth/token接口获取token。,9、A系统获取到token后,首先会对token进行解析,并使用配置的公钥对token进行校验(非对称加密),如果校验通过,则将token设置到上下文,下次访问请求时直接从上下文中获取。,10、A系统处理完上下问会话之后重定向到登录前请求的受保护资源链接。,1、用户通过浏览器访问B系统被保护的资源链接。,2、B系统判断当前会话是否登录,如果没有登录则跳转到B系统登录地址/login。,3、B系统首次接收到/login请求时没有state和code参数,此时B系统拼接系统配置的单点登录服务器授权url,并重定向至授权链接。,4、单点登录服务器判断此会话是否登录,因上面访问A系统时登陆过,所以此时不会再返回登录界面。,5、单点登录服务器重定向到B系统的/login链接,此时链接带有code和state参数。,6、B系统再次接收到/login请求,此请求携带state和code参数,系统B通过OAuth2RestTemplate请求单点登录服务端/oauth/token接口获取token。,7、B系统获取到token后,首先会对token进行解析,并使用配置的公钥对token进行校验(非对称加密),如果校验通过,则将token设置到上下文,下次访问请求时直接从上下文中获取。,8、B系统处理完上下问会话之后重定向到登录前请求的受保护资源链接。,1、用户通过浏览器访问单点登录被保护的资源链接。,2、SpringSecurity通过上下文判断是否登录(SpringSecurity单点登录服务端和客户端默认都是基于session的),如果没有登录则跳转到单点登录客户端地址/login。,3、单点登录客户端OAuth2ClientAuthenticationProcessingFilter拦截器通过上下文获取token,因第一次访问单点登录客户端/login时,没有code和state参数,所以抛出UserRedirectRequiredException异常。,4、单点登录客户端捕获UserRedirectRequiredException异常,并根据配置文件中的配置,组装并跳转到单点登录服务端的授权链接/oauth/authorize,链接及请求中会带相关配置参数。,5、单点登录服务端收到授权请求,根据session判断是否此会话是否登录,如果没有登录则跳转到单点登录服务器的统一登录界面(单点登录服务端也是根据session判断是否登录的,在这里为了解决微服务的session集群共享问题,引入了spring-session-data-redis)。,6、用户完成登录操作后,单点登录服务端重定向到单点登录客户端的/login链接,此时链接带有code和state参数。,7、再次用到第三步的OAuth2ClientAuthenticationProcessingFilter拦截器通过上下文获取token,此时上下文中肯定没有token,所以会通过OAuth2RestTemplate请求单点登录服务端/oauth/token接口使用重定向获得的code和state换取token。,8、单点登录客户端获取到token后,首先会对token进行解析,并使用配置的公钥对token进行校验(非对称加密),如果校验通过,则将token设置到上下文,下次访问请求时直接从上下文中获取。,9、单点登录客户端处理完上下问会话之后重定向到登录前请求的受保护资源链接。,当我们的gitegg-oauth作为授权服务器使用时,我们希望定制自己的登录页等信息,下面我们自定义登录、主页、错误提示页、找回密码页。其他需要的页面可以自己定义,比如授权确认页,我们此处业务不需要用户二次确认,所以这里没有自定义此页面。,在gitegg-oauth工程的pom.xml中添加Thymeleaf依赖,作为Spring官方推荐的模板引擎,我们使用Thymeleaf来实现前端页面的渲染展示。,在GitEggOAuthController中新增页面跳转路径:,在resources目录下新建static(静态资源)目录和templates(页面代码)目录,新增favicon.ico文件。,自定义登录页login.html代码:,自定义登录login.js代码:,修改web安全配置WebSecurityConfig,将静态文件添加到不需要授权就能访问。,修改Nacos配置,将新增页面访问路径添加到访问白名单,使资源服务器配置ResourceServerConfig中的配置不进行鉴权就能够访问,同时增加tokenUrls配置,此配置在网关不进行鉴权,但是需要OAuth2进行Basic鉴权,授权码模式必须要用到此鉴权。,因GitEgg框架使用用户名+密码再加密存储的密码,所以这里需要自定义登录过滤器来做相应处理,也可以用同样的方式新增手机验证码登录、扫码登录等功能。,spring-security-oauth2提供OAuth2授权服务器的同时也提供了单点登录客户端的实现,通用通过几行注解即可实现单点登录功能。,1、新建单点登录客户端工程,引入oauth2客户端相关jar包。,2、新建WebSecurityConfig类,添加@EnableOAuth2Sso注解。,3、配置单点登录服务端相关信息。,1、GitEgg框架中自定义了token返回格式,SpringSecurity获取token的/oauth/token默认返回的是ResponseEntity,自有系统登录和单点登录时需要做转换处理。,2、Gateway网关鉴权需要的公钥地址是gitegg-oauth/oauth/public_key,单点登录客户端需要公钥地址/oauth/token_key,两者返回的格式不一样,需注意区分。,3、请求/oauth/tonen和/oauth/token_key时,默认都需要使用Basic认证,也就是请求时需添加client_id和client_security参数。,GitEgg: GitEgg 是一款开源免费的企业级微服务应用开发框架,旨在整合目前主流稳定的开源技术框架,集成常用的最佳项目解决方案,实现可直接使用的微服务快速开发框架。,GitHub - wmz1930/GitEgg: GitEgg 是一款开源免费的企业级微服务应用开发框架,旨在整合目前主流稳定的开源技术框架,集成常用的最佳项目解决方案,实现可直接使用的微服务快速开发框架。,
© 版权声明
文章版权归作者所有,未经允许请勿转载。