spring-cloud-starter-oauth2搭建授權中心服務


A 抖音APP
B 微信APP
C 微信授權中心

 

1授權碼(authorization-code):
A前端跳轉C授權地址,授權中心喚醒B登錄后授權,跳轉指定的重定向地址(一般就是A)攜帶一個code,A后端再用client_secret、code獲取token 最最主流的應用模式

a.
http://127.0.0.1:8081/oauth/authorize?response_type=code&client_id=test&redirect_uri=http://127.0.0.1:8082/test&scope=read
b.
http://127.0.0.1:8082/test?code=drQ9y6
c.
http://127.0.0.1:8081/oauth/token?client_id=test&client_secret=test&grant_type=authorization_code&code=CGIFwy&redirect_uri=http://127.0.0.1:8082/test

 

 

 

 

 

 

 

 

 

 

 


2隱藏式(implicit):
A前端跳轉C授權地址,授權中心喚醒B登錄后授權,直接跳轉指定的重定向地址(一般就是A) #號攜帶token 適合純前端應用

http://127.0.0.1:8081/oauth/authorize?response_type=token&client_id=test&redirect_uri=http://127.0.0.1:8082/test&scope=read

 

 

3密碼式(password):
A前端直接要求用戶把登錄賬號密碼填充,然后請求C拿到token 非常不安全,適合高可信任的三方比如微服務網關zuul-gataway等
http://127.0.0.1:8081/oauth/token?grant_type=password&username=admin&password=admin&client_id=test&client_secret=test

 

 


4.客戶端憑證(client credentials):
明顯可以看出整個過程不涉及用戶信息,這種方式給出的令牌,是針對第三方應用的,而不是針對用戶的,即有可能多個用戶共享同一個令牌。
http://127.0.0.1:8081/oauth/token?grant_type=client_credentials&client_id=test&client_secret=test

 

 

 


實測tips

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
較新的版本需要注意授權服務器需要配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.requestMatchers().anyRequest()
.and()
.authorizeRequests()
.antMatchers("/oauth/**","/oauth/authorize").authenticated();
http.formLogin();
} authenticated 而不是 permitAll
否則提示
{"code":500,"msg":"User must be authenticated with Spring Security before authorization can be completed.","data":null,"timestamp":1603527083994}

同時,假如要在授權服務上做資源服務配置,
@EnableWebSecurity
@Order(2)

@EnableResourceServer
@Order(6)
即前者初始化要優先
否則提示
<oauth>
<error_description>Full authentication is required to access this resource</error_description>
<error>unauthorized</error>
</oauth>

 

參考文檔
http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html
https://blog.csdn.net/qq_34997906/article/details/89609297

 

 

后續測試方向

1.微服務整合,資源服務配置,打算網關就做純網關路由,授權中心不和用戶資源服務做關聯,甚至可以不注冊到eureka

2.權限范圍測試及各個模式異同

2020-10-28

完成微服務整合以后我們在資源服務上面開啟安全注解,這樣我們就能愉快的使用注解來細顆粒的控制權限了

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)

一、JSR-250注解
  @DenyAll 拒絕所有訪問
  @RolesAllowed({"USER", "ADMIN"})  該方法只要具有"USER", "ADMIN"任意一種權限就可以訪問。這里可以省 略前綴ROLE_,實際的權限可能是ROLE_ADMIN
注意

客戶端方式 client authorities以client表的authorities字段為准

授權碼、隱藏式、密碼登陸模式  authorities以user對應的role表為准

 
  @PermitAll 允許所有訪問
 
 
二、prePostEnabled注解
  @PreAuthorize:在方法執行之前執行,而且這里可以調用方法的參數,也可以得到參數值,這是利用JAVA8的參數名反射特性,如果沒用JAVA8,那么也可以利用Spring Security的@P標注參數,或者Spring Data的@Param標注參數。
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)")
void changePassword(@P("userId") long userId ){  }
這里表示在changePassword方法執行之前,判斷方法參數userId的值是否等於principal中保存的當前用戶的userId,或者當前用戶是否具有ROLE_ADMIN權限,兩種符合其一,就可以訪問該方法。
  @PostAuthorize:在方法執行之后執行,而且這里可以調用方法的返回值,如果EL為false,那么該方法也已經執行完了,可能會回滾。EL變量returnObject表示返回的對象。
@PostAuthorize
User getUser("returnObject.userId == authentication.principal.userId or hasPermission(returnObject, 'ADMIN')");
  @PreFilter:在方法執行之前執行,而且這里可以調用方法的參數,然后對參數值進行過濾或處理或修改,EL變量filterObject表示參數,如有多個參數,使用filterTarget注解參數。只有方法參數是集合或數組才行。(很少會用到,與分頁技術不兼容)

三、securedEnabled 注解
@GetMapping("/helloUser")
@Secured({"ROLE_normal","ROLE_admin"})
public String helloUser() {
    return "hello,user";
}

說明:擁有normal或者admin角色的用戶都可以方法helloUser()方法。另外需要注意的是這里匹配的字符串需要添加前綴“ROLE_“如果我們要求,只有同時擁有admin & noremal的用戶才能方法helloUser()方法,這時候@Secured就無能為力了。

 
參考 
 
 
還有一類根據client申請token時聲明申請的scope范圍(必須在分配可訪問的范圍內選擇)來控制權限。
比如我允許client有read write update create

 

 我在申請token的時候指定read update

 

此時如果資源服務器的scope要求write或者create的scope權限就無權訪問了。

 

  

 
總的來說有兩類權限控制方式role/authorities(細顆粒,看user有什么role當客戶端模式的時候看client有什么authorities)  scope(粗顆粒看client申請了什么scope)
 
 

3.自定義登錄授權

 增2020-11-03

經過實踐查閱認證自定義登錄的概念有兩類,第一種是針對Oauth四種模式的擴展,即獲取token的擴展,第二種是針對授權碼模式和隱藏模式在跳轉認證服務時登錄認證時的自定義擴展,即spring security的登錄擴展。兩種都能集成短信、社交、掃碼、用戶密碼的擴展,前者對調用者來說每次都要改調用方式,而后者授權流程不變,只是在認證服務的登錄頁面提供多元登錄操作,只需要服務方去集成,調用者不需要做任何調整。說的有點抽象哈,請看下圖。

 

a.縱向擴展比較簡單,繼承AbstractTokenGranter重寫getOAuth2Authentication方法,然后將新的授權方法塞入。

 

 效果如下

 

 

 

b.橫向擴展,需要自定義登陸頁面和授權頁面(后期接入許多認證方式都要加對應前端的東西),指定spring security的登陸頁面地址和UsernamePasswordAuthenticationFilter的目標過濾地址,如果新增擴展自定義的過濾器需要注釋否則會走再經過上面提到spring security的UsernamePasswordAuthenticationFilter。還要再指定經過過濾器以后跳轉的授權頁地址替換默認的“oauth/comfirm_access”。

    

 

 

 

 

 

 然后校驗的核心就是MyUsernamePasswordAuthenticationFilter自定義過濾器和MyAuthenticationManager自定義的認證類,然后加入配置

 

 這樣授權碼和隱藏模式在登陸的時候可以自定義我們的規則,成功后點擊授權就可以發放code或者token了。

 

 

2021-01-29

嘗試將oauth服務接入eureka集群,gateway過濾認證且允許傳遞header。oauth自定義接口測試正常。前端通過gateway順利獲取到token。

再嘗試經過dateway授權碼模式獲取code時發現域名地址出現了變化。這里就涉及到eureka注冊服務的ip和主機名策略。

eureka:
instance:
prefer-ip-address: true
ip-address: localhost #為了讓授權碼模式跳轉在同一個域名 配置成和gateway同入口的域名
因為新老服務的關系,eureka client注冊存在差異。老版本默認ip注冊,新版本默認主機名注冊。導致gateway ip域名請求時的session在oauth主機名下跳轉登陸頁面獲取不到session
導致報錯404.把oauth的實例改成和gateway同一個域名ip可解決。

 


免責聲明!

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



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