springboot跨系统登录(springboot单点登录整合)

生活常识 2023-04-20 13:50生活常识www.baidianfengw.cn

拦截超时是成功了还是没成功 SpringBoot 跨系统单点登陆的实现 | CSDN 博文精选

作者 | 代码忘烦恼

责编 | 屠敏

出品 | CSDN 博客

什么是单点登陆

单点登录(英语Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一退出(single sign-off)就是指,只需要单一的退出动作,就可以结束对于多个系统的访问权限。

单点登陆带来的好处

降低访问第三方网站的风险(不存储用户密码,或在外部管理)

减少因不同的用户名和密码组合而带来的密码疲劳

减少为相同的身份重新输入密码所花费的时间

因减少与密码相关的调用IT服务台的次数而降低IT成本

单点登陆技术

现在很多语言都拥有自己的单点登陆实现方案,本次案例中我们用SpringBoot Oauh2来实现跨系统的单点登陆。

单点登陆流程

你的项目可能有很多个模块,如订单管理、商户管理、会员管理、财务管理,这些都是需要登陆后才能访问,当我只要登陆一次,其它的系统都能访问。

图源于

上图是最清晰描述单点登陆的流程,如上图就是最基本的单点登陆流程。

oauth2 的四种模式

密码模式(resource owner password credentials)

授权码模式(authorization code)

简化模式(implicit)

客户端模式(client credentials)

我们一般都用授权码模式 这个模式用的人也最多。

这几种模式如果想要了解的更清楚可以看阮一峰老师的oauth2(http://www.ruanyifeng.com/blog/2014/05/oauth_0.html)。

单点登陆准备工作

我们创建一个叫spring_sso_parent 普通的maven工程 作为整个项目的父工程,创建好后,删除src目录,并且修改pom.xml的依赖

spring_sso_parent 父工程的依赖如下

lt?xml version=\"1.0\" encoding=\"UTF-8\"?gtltproject xmlns=\"http://maven.apache.org/POM/4.0.0\"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"gtltmodelVersiongt4.0.0lt/modelVersiongtlt!-- 父工程 --gtltparentgtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-parentlt/artifactIdgtltversiongt2.1.6.RELEASElt/versiongtltrelativePath/gtlt/parentgtltgroupIdgtcn.com.scitclt/groupIdgtltartifactIdgtspring_sso_parentlt/artifactIdgtltversiongt1.0-SNAPSHOTlt/versiongtltpackaginggtwarlt/packaginggtlt!-- 通用配置 --gtltpropertiesgtltproject.build.sourceEncodinggtUTF-8lt/project.build.sourceEncodinggtltproject.reporting.outputEncodinggtUTF-8lt/project.reporting.outputEncodinggtltjava.versiongt1.8lt/java.versiongtlt!-- spring oauth2 版本 --gtltoauth.versiongt2.3.6.RELEASElt/oauth.versiongtlt!-- Spring Security OAuth2 AutoConfigure 版本 --gtltoauth-auto.versiongt2.1.6.RELEASElt/oauth-auto.versiongtlt/propertiesgtlt/projectgt

开始编写单点登陆

我们在spring_sso_parent 父工程中 添加一个子模块叫oauth_server的SpringBoot工程,依赖如下

lt?xml version=\"1.0\" encoding=\"UTF-8\"?gtltproject xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"gtltmodelVersiongt4.0.0lt/modelVersiongtltparentgtltgroupIdgtcn.com.scitclt/groupIdgtltartifactIdgtspring_sso_parentlt/artifactIdgtltversiongt1.0-SNAPSHOTlt/versiongtlt/parentgtltgroupIdgtcn.com.scitclt/groupIdgtltartifactIdgtoauth_serverlt/artifactIdgtltversiongt0.0.1-SNAPSHOTlt/versiongtltnamegtoauth_serverlt/namegtltpackaginggtwarlt/packaginggtltdescriptiongtthis is oauth2 serverlt/descriptiongtltdependenciesgtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-weblt/artifactIdgtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-thymeleaflt/artifactIdgtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.security.oauthlt/groupIdgtltartifactIdgtspring-security-oauth2lt/artifactIdgtltversiongt${oauth.version}lt/versiongtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-devtoolslt/artifactIdgtltscopegtruntimelt/scopegtltoptionalgttruelt/optionalgtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-testlt/artifactIdgtltscopegttestlt/scopegtlt/dependencygtlt/dependenciesgtltbuildgtltpluginsgtltplugingtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-maven-pluginlt/artifactIdgtlt/plugingtlt/pluginsgtlt/buildgtlt/projectgt

需要注意的是这里的SpringBoot 版本使用的是父模块的版本

ltparentgtltgroupIdgtcn.com.scitclt/groupIdgtltartifactIdgtspring_sso_parentlt/artifactIdgtltversiongt1.0-SNAPSHOTlt/versiongtlt/parentgt

我们在oauth_server 中创建一个config的包,并且创建一个WebSecurityConfig的类

@Configuration@Order(1)public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.requestMatchers.antMatchers(\"/login\").antMatchers(\"/oauth/authorize\").and.authorizeRequests.anyRequest.authenticated.and.formLogin.loginPage(\"/login\").permitAll.and.csrf.disable}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//使用内存模拟数据库查询的用户auth.inMemoryAuthentication //内存认证.withUser(\"admin\")//admin 内存认证用户名.password(passwordEncoder.encode(\"123456\"))//被加密的123456密码.roles(\"ADMIN\")//ROLE_ADMIN的角色}@Beanpublic PasswordEncoder passwordEncoder {return new BCryptPasswordEncoder}}

这个类使用了两个注解,@Configuration 让这个类成为了一个配置类, @Order(1) 这个注解是优先级,使用优先级来加载。

http.requestMatchers.antMatchers(\"/login\").antMatchers(\"/oauth/authorize\")

http.requestMatchers 这个 下配置的就是security 接收以什么样的请求,我们这里只接受/login和/oauth/authorize的请求 。

.authorizeRequests.anyRequest.authenticated

这两句配置的意思是除了以上请求所有的请求都需要身份认证才能访问。

.formLogin.loginPage(\"/login\").permitAll.and.csrf.disable

这几个配置的意思是采用form表单登陆默认登陆页面是/login,任何人都能访问,关闭csrf的保护。

@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//使用内存模拟数据库查询的用户auth.inMemoryAuthentication.withUser(\"admin\").password(passwordEncoder.encode(\"123456\")).roles(\"ADMIN\")}

这里采用的是AuthenticationManagerBuilder 允许内存验证,这里我添加了一个用户名为admin 密码是 123456,角色是ADMIN的 一个用户 来模拟数据库查询的用户信息。

@Beanpublic PasswordEncoder passwordEncoder {return new BCryptPasswordEncoder}

PasswordEncoder 是Spring 官方提供的一个md5 密码加密器,一般用于密码的加密。

这个就是WebSecurityConfig的配置

下面我们在config中继续创建一个叫OauthServerConfig的类

@Configuration@EnableAuthorizationServerpublic class OauthServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder@Overridepublic void configure(final AuthorizationServerSecurityConfigurer security) throws Exception {security.tokenKeyAccess(\"permitAll\").checkTokenAccess(\"isAuthenticated\")}@Overridepublic void configure(final ClientDetailsServiceConfigurer clients)throws Exception {clients.inMemory.withClient(\"handleCilentId\")//客户端id.secret(passwordEncoder.encode(\"secret\"))//客户端密钥.authorizedGrantTypes(\"authorization_code\")//授权码模式.scopes(\"user_\") //授权范围.autoApprove(true)//开启自动授权.redirectUris(\"http://localhost:8882/login\") //认证成功重定向.accessTokenValiditySeconds(10)//设置超时时间}}

这个类上也使用了两个注解,@Configuration 这个注解成为Spring的一个配置类,@EnableAuthorizationServer 注解是开启授权服务器认证。

这个类继承了AuthorizationServerConfigurerAdapter 这个类提供了授权服务器策略。

这里我们实现了两个configure 认证策略 ,分别是AuthorizationServerSecurityConfigurer 和 ClientDetailsServiceConfigurer,而AuthorizationServerSecurityConfigurer提供了十几个配置的 ,这里我们不会多去深入。

其中 tokenKeyAccess意思是oauth2授权服务器会提供一个/oauth/token_key的url来供资源服务器获取公钥,这个 就是配置获取公钥的权限范围,它使用的是SpEL表达式且默认不开启, 这里我们使用的是permitAll,让本身的oauth的访问不需要授权。

checkTokenAccess意思是授权服务器提供一个/oauth/check_token的url来供资源服务器解码令牌,该 就是配置权限范围,同样使用的是SpEL表达式且默认不开启,我们这里设置的是 isAuthenticated,检查access_token需要进行授权。

当客户端向认证服务器认证的时候,我们需要判断这个客户端是否通过了认证那么就要使用ClientDetailsServiceConfigurer 它提供了三种认证方式

clients.withClientDetails 使用数据库认证

clients.jdbc: 传入一个dataSource 这里可以使用自定义的dataSource

clients.inMemory内存认证 相当于将认证信息 写死

这样我们就将授权服务器配置好了。

下面我们创建一个controller的包。

创建一个LoginController 登陆的控制器

@Controllerpublic class LoginController {@GetMapping(\"/login\")public String loginPage {return \"login\"}}

这里返回的是一个login的 html 页面

lt!DOCTYPE htmlgtlthtml lang=\"en\"gtltheadgtltmeta charset=\"UTF-8\"gtlttitlegtloginlt/titlegtlt/headgtltbodygtlth1gt标准登陆lt/h1gtltform action=\"/auth/login\" method=\"post\"gtusername: ltinput type=\"text\" name=\"username\"/gt ltbr/gtpassword: ltinput type=\"password\" name=\"password\"/gt ltbr/gtltbutton type=\"submit\"gt登陆lt/buttongtlt/formgtlt/bodygtlt/htmlgt

在创建一个UserInfoController 用于获取认证成功的用户信息

@RestControllerpublic class UserInfoController {private Logger logger = LoggerFactory.getLogger(this.getClass)@RequestMapping(\"/user\")public ResponseEntityltObjectgt getUser(Principal principal) {logger.(\"principal:\" + principal)return new ResponseEntityltObjectgt(principal, HttpStatus.OK)}}

applicatin.yml 配置

server:port: 8880servlet:context-path: /auth

然后我们创建2个客户端分别是oauth_client1 和 oauth_client2

oauth_client1 的依赖如下

lt?xml version=\"1.0\" encoding=\"UTF-8\"?gtltproject xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"gtltmodelVersiongt4.0.0lt/modelVersiongtltparentgtltgroupIdgtcn.com.scitclt/groupIdgtltartifactIdgtspring_sso_parentlt/artifactIdgtltversiongt1.0-SNAPSHOTlt/versiongtlt/parentgtltgroupIdgtcn.com.scitclt/groupIdgtltartifactIdgtoauth_clinet1lt/artifactIdgtltversiongt0.0.1-SNAPSHOTlt/versiongtltpackaginggtwarlt/packaginggtltnamegtoauth_clinet1lt/namegtltdescriptiongtthis is client1lt/descriptiongtltpropertiesgtltjava.versiongt1.8lt/java.versiongtlt/propertiesgtltdependenciesgtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-thymeleaflt/artifactIdgtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-weblt/artifactIdgtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-securitylt/artifactIdgtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.security.oauth.bootlt/groupIdgtltartifactIdgtspring-security-oauth2-autoconfigurelt/artifactIdgtltversiongt${oauth-auto.version}lt/versiongtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-devtoolslt/artifactIdgtltscopegtruntimelt/scopegtltoptionalgttruelt/optionalgtlt/dependencygtltdependencygtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-starter-testlt/artifactIdgtltscopegttestlt/scopegtlt/dependencygtlt/dependenciesgtltbuildgtltpluginsgtltplugingtltgroupIdgtorg.springframework.bootlt/groupIdgtltartifactIdgtspring-boot-maven-pluginlt/artifactIdgtlt/plugingtlt/pluginsgtlt/buildgtlt/projectgt

同样创建一个config 包 并且创建一个 Oauth2ClientSeurityConfig这个类

@Configuration@EnableOAuth2Ssopublic class Oauth2ClientSeurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf.disable //关闭csrf保护.antMatcher(\"/\") //使用以任意开头的url.authorizeRequests // 配置路径拦截,表明路径访问所对应的权限,角色,认证信息.antMatchers(\"/\", \"/login\") //控制不同的url接受不同权限的用户访问.permitAll// 允许所有人访问.anyRequest.authenticated //除了以上请求都需要身份认证}}

这个类继承了 WebSecurityConfigurerAdapter 这个SpringSecurity的适配器,实现了HttpSecurity 的 configure 。这个类也是两个注解 @Configuration 成为一个配置类,@EnableOAuth2Sso 启用Oauth2的单点登陆。

我们再创建一个controller 包 ,并且创建一个 InfoController

@Controllerpublic class InfoController {@GetMapping(\"/getUser\")public ResponseEntityltObjectgt userPage(Principal principal) {//客户端认证成功后返回这个用户信息return new ResponseEntityltObjectgt(principal, HttpStatus.OK)}@GetMapping(\"/\")public String indexPage {return \"index\"}}

index.html 页面

lt!DOCTYPE htmlgtlthtml lang=\"en\"gtltheadgtltmeta charset=\"UTF-8\"gtlttitlegtindexlt/titlegtlt/headgtltbodygtlth1gt请登录授权lt/h1gtlta href=\"/getUser\"gtloginlt/agtlt/bodygtlt/htmlgt

application.yml

auth-server: http://localhost:8880/authserver:port: 8881servlet:context-path: /security:basic:enabled: falseoauth2:client:clientId: handleCilentIdclientSecret: secretaccessTokenUri: ${auth-server}/oauth/tokenuserAuthorizationUri: ${auth-server}/oauth/authorizeresource:userInfoUri: ${auth-server}/userspring:thymeleaf:cache: false

auth-server是目标认证服务器

clientId目标认证服务器设置的客户端id

clientSecret目标认证服务器设置的密码

accessTokenUri从目标认证服务器获取令牌token

userAuthorizationUri从目标认证服务器请求授权默认url是/oauth/authorize

userInfoUri: 从目标认证服务器上将认证信息Principal通过形参绑定的 通过URL的方式获取用户信息。

oauth_client2配置和 oauth_client1是一样的。

我们启动 认证服务器oauth_server 和两个客户端 oauth_client1 和 oauth_client2。Chrome 浏览器访问 localhost:8881

当我们点击login的时候会跳转到认证服务器进行登陆授权

授权成功后 返回了这个用户的所有的信息

我们再去访问localhost:8082

当我点击登陆的时候 ,并没有出现登陆授权,直接拿到了用户信息

注意这里我们不管是访问客户端1还是客户端2 ,还是n多个客户端,只要有一个授权成功 那么访问其它的客户端就不需要登陆 就能访问相关的rest服务了。

oauth2 实现的单点登陆并不是很复杂,归根结底,Spring帮我们做了太多的底层实现,让我们实现起来非常的简单 实现几个接口就可以搞定授权服务器的配置,客户端的配置也非常的简单。

现在我们流行看到了如百度,我登陆了百度,那么就可以直接访问百度贴吧,百度糯米等。单点登陆运用已经使用的非常的广泛。所以我认为掌握单点登陆是十分有必要的。

GitHub 源码地址https://github.com/zhoubiao188/spring_cloud_study

原文https://blog.csdn.net/qwe86314/article/details/97610020

声明本文系CSDN博客原创文章,转载请联系原作者。

【End】

5G进入元年,物联网发展愈加火爆!你是否身怀绝技、却无人知晓;别让你的IoT项目再默默无闻了!继之一届AI优秀案例评选活动之后,2019年案例评选活动再度升级,CSDN将评选出TOP 50优秀IoT案例,赶快扫码参与评选吧!重磅福利,等你来领!

springboot单点登录整合 springboot单点登录实现

Copyright@2015-2025 白癜风网版板所有