基于JWT實現(xiàn)SSO單點登錄流程圖解
一、基于JWT實現(xiàn)SSO單點登錄原理
1、什么是單點登錄
所謂單點登錄就是有多個應(yīng)用部署在不同的服務(wù)器上,只需登錄一次就可以互相訪問不同服務(wù)器上的資源。
2、單點登錄流程

當(dāng)一個訪問請求發(fā)給應(yīng)用A,如果這個請求需要登錄以后才能訪問,那么應(yīng)用A就會向認(rèn)證服務(wù)器請求授權(quán),這時候就把用戶引導(dǎo)到認(rèn)證服務(wù)器上。用戶在認(rèn)證服務(wù)器上完成認(rèn)證并授權(quán)。認(rèn)證授權(quán)完成后,認(rèn)證服務(wù)器返回給應(yīng)用A一個授權(quán)碼,應(yīng)用A攜帶授權(quán)碼到認(rèn)證服務(wù)器請求令牌,認(rèn)證服務(wù)器返回應(yīng)用A一個JWT,應(yīng)用A解析JWT里面的信息,完成登錄。這是一個標(biāo)準(zhǔn)的OAuth2的授權(quán)碼流程。
走完認(rèn)證流程后,給出去的JWT實際上里面包含的就是當(dāng)前用戶在認(rèn)證服務(wù)器上登錄以后用戶的認(rèn)證信息,應(yīng)用A解析JWT后,自己生成一個經(jīng)過認(rèn)證的Authentication放到它的SpringSecurity和SecurityContext里面。
當(dāng)訪問應(yīng)用服務(wù)器B的時候,同樣引導(dǎo)用戶去認(rèn)證服務(wù)器請求授權(quán)(不需要登錄),用戶授權(quán)可以用登錄的信息去訪問應(yīng)用B,后面同樣是授權(quán)碼流程,返回JWT給應(yīng)用B。兩個應(yīng)用返回不同的JWT,但是解析出的信息是一樣的。
二、實現(xiàn)單點登錄
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、認(rèn)證服務(wù)(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)的時候需要身份認(rèn)證
}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("shxiang");//設(shè)置秘鑰
return accessTokenConverter;
}
}
6)SsoServerApplication.java
@SpringBootApplication
public class SsoServerApplication {
public static void main(String[] args) {
SpringApplication.run(SsoServerApplication.class, args);
}
}
3、應(yīng)用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 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、應(yīng)用2(sso-client2)
1)pom.xml,同上
2)application.properties,類比應(yīng)用1修改
3)index.html,類比應(yīng)用1修改
4)SsoClient2Application.java,同上
5、測試
1)瀏覽器輸入:127.0.0.1:8080/client1/index.html

2)用戶名隨便輸入,密碼輸入123456

3)點擊Authorize

4)點擊超級鏈接訪問Client2

5)點擊Authorize

認(rèn)證成功,后面點擊兩個超級鏈接可以任意訪問,無需登錄 、無需點擊Authorize。
注意:
1)雖是同一用戶,但是訪問http://127.0.0.1:8080/client1/user和http://127.0.0.1:8060/client2/user獲取的Token值不一樣。
2)實現(xiàn)跳過授權(quán),登錄后直接訪問,修改如下代碼:

3)表單登錄與httpBasic登錄,修改WebSecurityConfig.java中configure方法
httpBasic登錄:http.httpBasic().and().csrf().disable();
表單登錄:http.formLogin().and().authorizeRequests().anyRequest().authenticated();
4)重點:瀏覽器訪問要用127.0.0.1不要用localhost。要設(shè)置應(yīng)用路徑server.servlet.context-path =/xxxx,不能直接到端口號。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java實現(xiàn)定時讀取json文件里內(nèi)容的示例代碼
有時候我們會需要定時來讀取JSON配置文件里的內(nèi)容,來執(zhí)行一些業(yè)務(wù)邏輯上的操作,本文就介紹了Java實現(xiàn)定時讀取json文件里內(nèi)容的示例代碼,感興趣的可以了解一下2023-08-08
Spring Cloud Gateway 使用JWT工具類做用戶登錄校驗功能
這篇文章主要介紹了Spring Cloud Gateway 使用JWT工具類做用戶登錄校驗的示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
maven無法依賴spring-cloud-stater-zipkin的解決方案
這篇文章主要介紹了maven無法依賴spring-cloud-stater-zipkin如何解決,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-05-05

