您好,登錄后才能下訂單哦!
概 述
在前文《基于Spring Security和 JWT的權限系統設計》之中已經討論過基于 Spring Security和 JWT的權限系統用法和實踐,本文則進一步實踐一下基于 Spring Security Oauth3實現的多系統單點登錄(SSO)和 JWT權限控制功能,畢竟這個需求也還是蠻普遍的。
代碼已開源,放在文尾,需要自取
理論知識
在此之前需要學習和了解一些前置知識包括:
Spring Security:基于 Spring實現的 Web系統的認證和權限模塊
OAuth3:一個關于授權(authorization)的開放網絡標準
單點登錄 (SSO):在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統
JWT:在網絡應用間傳遞信息的一種基于 JSON的開放標準((RFC 7519),用于作為JSON對象在不同系統之間進行安全地信息傳輸。主要使用場景一般是用來在 身份提供者和服務提供者間傳遞被認證的用戶身份信息
要完成的目標
目標1:設計并實現一個第三方授權中心服務(Server),用于完成用戶登錄,認證和權限處理
目標2:可以在授權中心下掛載任意多個客戶端應用(Client)
目標3:當用戶訪問客戶端應用的安全頁面時,會重定向到授權中心進行身份驗證,認證完成后方可訪問客戶端應用的服務,且多個客戶端應用只需要登錄一次即可(謂之 “單點登錄 SSO”)
基于此目標驅動,本文設計三個獨立服務,分別是:
一個授權服務中心(codesheep-server)
客戶端應用1(codesheep-client1)
客戶端應用2(codesheep-client2)
多模塊(Multi-Module)項目搭建
三個應用通過一個多模塊的 Maven項目進行組織,其中項目父 pom中需要加入相關依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.8.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Cairo-RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
項目結構如下:
授權認證中心搭建
授權認證中心本質就是一個 Spring Boot應用,因此需要完成幾個大步驟:
pom中添加依賴
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth3</artifactId>
</dependency>
</dependen
項目 yml配置文件:
server:
port: 8085
servlet:
context-path: /uac
即讓授權中心服務啟動在本地的 8085端口之上
創建一個帶指定權限的模擬用戶
@Component
public class SheepUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
if( !"codesheep".equals(s) )
throw new UsernameNotFoundException("用戶" + s + "不存在" );
return new User( s, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_NORMAL,ROLE_MEDIUM"));
}
}
這里創建了一個用戶名為codesheep,密碼 123456的模擬用戶,并且賦予了 普通權限(ROLE_NORMAL)和 中等權限(ROLE_MEDIUM)
認證服務器配置 AuthorizationServerConfig
這里做的最重要的兩件事:一是 定義了兩個客戶端應用的通行證(sheep1和sheep2);二是 配置 token的具體實現方式為 JWT Token。
Spring Security安全配置 SpringSecurityConfig
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setHideUserNotFoundExceptions(false);
return authenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**")
.and()
.authorizeRequests()
.antMatchers("/oauth/**").authenticated()
.and()
.formLogin().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
}
客戶端應用創建和配置
本文創建兩個客戶端應用:codesheep-client1 和codesheep-client2,由于兩者類似,因此只以其一為例進行講解
SSO客戶端應用配置類 ClientWebsecurityConfigurer
@Configuration@EnableWebSecurity
br/>@EnableWebSecurity
br/>@EnableOAuth3Sso
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.anyRequest().authenticated();
}
}
復雜的東西都交給注解了!
application.yml配置
auth-server: http://localhost:8085/uac
server:
port: 8086
security:
oauth3:
client:
client-id: sheep1
client-secret: 123456
user-authorization-uri: ${auth-server}/oauth/authorize
access-token-uri: ${auth-server}/oauth/token
resource:
jwt:
key-uri: ${auth-server}/oauth/token_key
這里幾項配置都非常重要,都是需要和前面搭建的授權中心進行通信的
創建測試控制器 TestController
@RestController
public class TestController {
@GetMapping("/normal")
@PreAuthorize("hasAuthority('ROLE_NORMAL')")
public String normal( ) {
return "normal permission test success !!!";
}
@GetMapping("/medium")
@PreAuthorize("hasAuthority('ROLE_MEDIUM')")
public String medium() {
return "medium permission test success !!!";
}
@GetMapping("/admin")
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public String admin() {
return "admin permission test success !!!";
}
}
此測試控制器包含三個接口,分別需要三種權限(ROLE_NORMAL、ROLE_MEDIUM、ROLE_ADMIN),待會后文會一一測試看效果
實驗驗證
啟動授權認證中心 codesheep-server(啟動于本地8085端口)
啟動客戶端應用 codesheep-client1 (啟動于本地8086端口)
啟動客戶端應用 codesheep-client2 (啟動于本地8087端口)
首先用瀏覽器訪問客戶端1 (codesheep-client1) 的測試接口:localhost:8086/normal,由于此時并沒有過用戶登錄認證,因此會自動跳轉到授權中心的登錄認證頁面:http://localhost:8085/uac/login:
![](https://s1.51cto.com/images/blog/201905/07/95f2c5660545deea5998d79ab67e831f.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
![](https://s1.51cto.com/images/blog/201905/07/1110eb56499a673f4ea2edd404fa683a.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
![](https://s1.51cto.com/images/blog/201905/07/9b6c8a7647900c9b1be37d085d5bfd08.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
![](https://s1.51cto.com/images/blog/201905/07/856b231c3a171270aa8fa0876f93ef3a.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
這就驗證了單點登錄SSO的功能了!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。