一、基于JWT实现SSO单点登录原理
1、什么是单点登录
所谓单点登录就是有多个应用部署在不同的服务器上,只需登录一次就可以互相访问不同服务器上的资源。
2、单点登录流程
当一个访问请求发给应用A,如果这个请求需要登录以后才能访问,那么应用A就会向认证服务器请求授权,这时候就把用户引导到认证服务器上。用户在认证服务器上完成认证并授权。认证授权完成后,认证服务器返回给应用A一个授权码,应用A携带授权码到认证服务器请求令牌,认证服务器返回应用A一个JWT,应用A解析JWT里面的信息,完成登录。这是一个标准的OAuth2的授权码流程。
走完认证流程后,给出去的JWT实际上里面包含的就是当前用户在认证服务器上登录以后用户的认证信息,应用A解析JWT后,自己生成一个经过认证的Authentication放到它的SpringSecurity和SecurityContext里面。
当访问应用服务器B的时候,同样引导用户去认证服务器请求授权(不需要登录),用户授权可以用登录的信息去访问应用B,后面同样是授权码流程,返回JWT给应用B。两个应用返回不同的JWT,但是解析出的信息是一样的。
二、实现单点登录
1、父工程(sso-demo)
1)pom.xml
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.4.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.1.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>1.0.10.RELEASE</version> </dependency> </dependencies> </dependencyManagement>
2、认证服务(sso-server)
1)pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency>
2)application.properties
server.port = 9999
server.servlet.context-path = /server
3)WebSecurityConfig.java
@EnableWebSecurity @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic().and().csrf().disable(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
4)MyUserDetailsService.java
@Component public class MyUserDetailsService implements UserDetailsService{ @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("登录用户名:"+username); String password = passwordEncoder.encode("123456"); return new User(username,password,true,true,true,true, AuthorityUtils.commaSeparatedStringToAuthorityList("all")); } }
5)SsoAuthorizationServerConfig.java
@Configuration @EnableAuthorizationServer public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("appclient_1").secret(passwordEncoder.encode("client1_123456")) .authorizedGrantTypes("authorization_code","refresh_token") .scopes("all") .redirectUris("http://127.0.0.1:8080/client1/login") .and() .withClient("appclient_2").secret(passwordEncoder.encode("client2_123456")) .authorizedGrantTypes("authorization_code","refresh_token") .scopes("all") .redirectUris("http://127.0.0.1:8060/client2/login"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter()); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.tokenKeyAccess("isAuthenticated()");//访问tokenKey(秘钥shxiang)的时候需要身份认证 } @Bean public TokenStore jwtTokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("shxiang");//设置秘钥 return accessTokenConverter; } }
6)SsoServerApplication.java
@SpringBootApplication public class SsoServerApplication { public static void main(String[] args) { SpringApplication.run(SsoServerApplication.class, args); } }
3、应用1(sso-client1)
1)pom.xml,同上
2)application.properties
security.oauth2.client.client-id = appclient_1 security.oauth2.client.client-secret = client1_123456 security.oauth2.client.user-authorization-uri = http://127.0.0.1:9999/server/oauth/authorize security.oauth2.client.access-token-uri = http://127.0.0.1:9999/server/oauth/token security.oauth2.resource.jwt.key-uri = http://127.0.0.1:9999/server/oauth/token_key server.port=8080 server.servlet.context-path =/client1
3)index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>SSO Client1</title> </head> <body> <h1>SSO Demo Client1</h1> <a href="http://127.0.0.1:8060/client2/index.html" rel="external nofollow" >访问Client2</a> </body> </html>
4)SsoClient1Application.java
@SpringBootApplication @RestController @EnableOAuth2Sso public class SsoClient1Application { public static void main(String[] args) { SpringApplication.run(SsoClient1Application.class, args); } @GetMapping("/user") public Authentication user(Authentication user) { return user; } }
4、应用2(sso-client2)
1)pom.xml,同上
2)application.properties,类比应用1修改
3)index.html,类比应用1修改
4)SsoClient2Application.java,同上
5、测试
1)浏览器输入:127.0.0.1:8080/client1/index.html
2)用户名随便输入,密码输入123456
3)点击Authorize
4)点击超级链接访问Client2
5)点击Authorize
认证成功,后面点击两个超级链接可以任意访问,无需登录 、无需点击Authorize。
注意:
1)虽是同一用户,但是访问http://127.0.0.1:8080/client1/user和http://127.0.0.1:8060/client2/user获取的Token值不一样。
2)实现跳过授权,登录后直接访问,修改如下代码:
3)表单登录与httpBasic登录,修改WebSecurityConfig.java中configure方法
httpBasic登录:http.httpBasic().and().csrf().disable();
表单登录:http.formLogin().and().authorizeRequests().anyRequest().authenticated();
4)重点:浏览器访问要用127.0.0.1不要用localhost。要设置应用路径server.servlet.context-path =/xxxx,不能直接到端口号。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
我有一个关于JWT的SSO流的简单问题 假设我们有单独的授权服务器,它为客户端应用程序/服务器和资源服务器提供JWT,客户端尝试使用该令牌访问该服务器。 问题是,资源服务器应该自己验证令牌(例如,与Auth server共享私有证书),还是应该请求Auth server为每个客户端请求验证JWT?
问题内容: 我想使用Django为我们当前使用的多个应用程序实现单一登录(SSO)。如何使用Django实现SSO?是否有可用于实施SSO的Django软件包? 请帮忙谢谢 问题答案: 我们正在使用OpenAM。 http://forgerock.com/openam.html OpenAM Cookie表示用户已通过身份验证。 为此的身份验证后端非常简单。少于50行代码。 https://doc
本文向大家介绍golang实现单点登录系统(go-sso),包括了golang实现单点登录系统(go-sso)的使用技巧和注意事项,需要的朋友参考一下 这是一个基于Go语言开发的单点登录系统,实现手机号注册、手机号+验证码登录、手机号+密码登录、账号登出等功能,用户认证采用cookie和jwt两种方式。收发短信相关方法已提供,仅需根据短信通道提供商提供的接口做相应的参数配置即可使用。 环境介绍 g
本文向大家介绍asp.net简单实现单点登录(SSO)的方法,包括了asp.net简单实现单点登录(SSO)的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了asp.net简单实现单点登录(SSO)的方法。分享给大家供大家参考,具体如下: 单点登录(Single Sign On , 简称 SSO )是目前比较流行的服务于企业业务整合的解决方案之一, SSO 使得在多个应用系统中,用户只
web上有大量关于使用JWT()进行身份验证的信息。但是我仍然没有找到关于在多域环境中为单点登录解决方案使用JWT令牌时流程应该是什么的清晰解释。 我工作的公司有很多网站在不同的主机。让我们使用example1.com和example2.com。我们需要一个单点登录解决方案,这意味着如果一个用户在example1.com上进行身份验证,我们希望他也在example2.com上自动进行身份验证。 J
我已经搜索了很多关于如何实现SSO的好文档,因为我是这个领域的初学者。但被网上提供的文件弄糊涂了。是否有任何文档可以帮助我指导:如何创建/配置IDP、SP、如何实现SSO? 我的web应用程序使用Java 8、angular JS、JSP、Spring(带注释)、Hibernet、Maven、JBOSS。 提前感谢您的时间。