spring boot:spring security+oauth2+sso+jwt實現單點登錄(spring boot 2.3.3)


一,sso的用途 ?

1,如果有多個應用系統,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。
不需要每次輸入用戶名稱和用戶密碼,
也不需要創建並記憶多套用戶名稱和用戶密碼。

2,系統管理員只需維護一套統一的用戶賬號,方便、簡單。
而不必管理很多套的用戶賬號。

3, 如果需要開發新的應用系統,可以直接使用單點登錄平台的用戶認證服務,簡化開發流程。

4,oauth和sso的區別:

   oauth2解決的是服務提供方(微信等)給第三方應用授權的問題,
   sso解決的是大型系統中各個子系統如何共享登陸狀態的問題

 

說明:劉宏締的架構森林是一個專注架構的博客,地址:https://www.cnblogs.com/architectforest

         對應的源碼可以訪問這里獲取: https://github.com/liuhongdi/

說明:作者:劉宏締 郵箱: 371125307@qq.com

 

二,演示項目的相關信息

1,項目地址:

https://github.com/liuhongdi/securityssojwt

 

2,功能說明:

           演示了基於oauth2實現sso

 

3,項目結構:如圖:

 

 

三,配置文件說明

1,ssoserver的 pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
       <!--security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--oauth2-->
        <dependency>
<groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.5.0.RELEASE</version>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.1.1.RELEASE</version>
        </dependency>

        <!--jaxb-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>

 

2,ssoclient1的 pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--oauth2-->
        <dependency><groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.5.0.RELEASE</version>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.1.1.RELEASE</version>
        </dependency>
        <!--oauth2 autoconfigure-->
        <dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.3.3.RELEASE</version>
        </dependency>

 

3,ssoclient2的 pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--oauth2-->
        <dependency><groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.5.0.RELEASE</version>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.1.1.RELEASE</version>
        </dependency>
        <!--oauth2 autoconfigure-->
        <dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.3.3.RELEASE</version>
        </dependency>

 

4,ssoserver的application.properties

server.port = 8080
server.servlet.context-path = /server
spring.security.user.password=123456

#error
server.error.include-stacktrace=always
#log
logging.level.org.springframework.web=trace
logging.level.org.springframework.security=debug

 

5,ssoclient1的application.properties

security.oauth2.client.client-id=client1
security.oauth2.client.client-secret=client1secrect
#需要認證時候跳轉的地址
security.oauth2.client.user-authorization-uri=http://127.0.0.1:8080/server/oauth/authorize
#請求令牌地址
security.oauth2.client.access-token-uri=http://127.0.0.1:8080/server/oauth/token
#解析
security.oauth2.resource.jwt.key-uri=http://127.0.0.1:8080/server/oauth/token_key
#security.oauth2.resource.jwt.key-value=imooc
#sso
server.port=8081
server.servlet.context-path=/client1

 

6,ssoclient2的application.properties

security.oauth2.client.client-id=client2
security.oauth2.client.client-secret=client2secrect
#需要認證時候跳轉的地址
security.oauth2.client.user-authorization-uri=http://127.0.0.1:8080/server/oauth/authorize
#請求令牌地址
security.oauth2.client.access-token-uri=http://127.0.0.1:8080/server/oauth/token
#解析
security.oauth2.resource.jwt.key-uri=http://127.0.0.1:8080/server/oauth/token_key
#sso
server.port=8082
server.servlet.context-path=/client2

 

四,java代碼說明:

1,ssoserver的WebSecurityConfig.java

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private SsoUserDetailsService ssoUserDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder()    {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(ssoUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().and().authorizeRequests().anyRequest().authenticated();
    }
}

 

2,ssoserver的SsoUserDetailsService.java:

@Component
public class SsoUserDetailsService implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    //本來應該從數據庫加載數據,此處供僅演示
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("----------------------loadUserByUsername");
        if (username.equals("laoliu") == false) {
           throw new UsernameNotFoundException("用戶名不存在");
        }
        return new User(username, passwordEncoder.encode("123456"),
                AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
    }
}

 

3,ssoserver的SsoAuthorizationServerConfig.java:

@Configuration
@EnableAuthorizationServer
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    //配置供訪問的客戶端的賬戶
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                // 注冊一個客戶端,設置名稱
                .withClient("client1")
                // 設置客戶端陰匙
                .secret(new BCryptPasswordEncoder().encode("client1secrect"))
                // 對應客戶端登錄請求URI
                .redirectUris("http://127.0.0.1:8081/client1/login")
                // 授權方式
                .authorizedGrantTypes("authorization_code", "password", "refresh_token")
                // 授權范圍
                .scopes("all")
                // 是否自動同意,如果采用非自動同意,則需要用戶手動授權
                .autoApprove(true)
                .and().
                withClient("client2")
                .redirectUris("http://127.0.0.1:8082/client2/login")
                .secret(new BCryptPasswordEncoder().encode("client2secrect"))
                .authorizedGrantTypes("authorization_code", "password", "refresh_token")
                .scopes("all")
                .autoApprove(true);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("isAuthenticated()");
    }

    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        //指定signkey
        converter.setSigningKey("liuhongdi");
        return converter;
    }
}

 

4,ssoclient1的HomeController.java

@Controller
@RequestMapping("/home")
public class HomeController {
    //查看登錄后的用戶信息
    @RequestMapping("/session")
    @ResponseBody
    public String getsession(){
        //session
        String userone = SessionUtil.getCurrentUserName();
        System.out.println("user:"+userone);
        if (userone == null) {
            return "not login";
        } else {
            return userone;
        }
    }
}

 

5,ssoclient1的SessionUtil.java

public class SessionUtil {
    //得到security所保存的用戶
    public static String getCurrentUserName(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication.isAuthenticated() && !(authentication instanceof AnonymousAuthenticationToken)) {
            Object principal = authentication.getPrincipal();
            //System.out.println(principal);
            if (principal instanceof String) {
                return (String)principal;
            } else if (principal instanceof UserDetails) {
                String currentuser = ((UserDetails) principal).getUsername();
                return currentuser;
            } else {
                //System.out.println("not instanceof UserDetails");
            }
            return null;
        }
        return null;
    }
}

 

6,其他非關鍵代碼可訪問github查看

 

五,測試效果

1,按以下順序啟動三個模塊:

   ssoserver

   ssoclient1

   ssoclient2

 

2,先訪問client1,

http://127.0.0.1:8081/client1/home/session

會跳轉到:

http://127.0.0.1:8080/server/login

如圖:

 我們輸入用戶名 laoliu,密碼 123456

這個是寫死在代碼中的演示賬號

登錄后會跳轉到:

 

 這個url會打印當前登錄用戶的用戶名

我們新打開一個標簽頁:

http://127.0.0.1:8082/client2/home/session

我們之前並未從client2登錄,查看效果:

 

 可以看到也已經登錄

 

3,通過html頁面跳轉訪問:

http://127.0.0.1:8081/client1/index.html

返回:

 

 點擊 訪問client2 的鏈接

 

 可正常訪問

 

六,查看spring boot版本

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.3.RELEASE)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM