1. 程式人生 > >Spring security oauth2最簡單入門環境搭建--二、乾貨

Spring security oauth2最簡單入門環境搭建--二、乾貨

轉載自:http://wwwcomy.iteye.com/blog/2230265


友情提示 學習曲線:spring+spring mvc+spring security+Oauth2基本姿勢,如果前面都沒看過請及時關閉本網頁。

我有信心我的這個blog應該是迄今為止使用spring security oauth2最簡單的hello world app介紹了,如果你下下來原始碼還看不懂,請留言。。 

其他能搜到的如http://blog.csdn.net/monkeyking1987/article/details/16828059這個哥們兒 
和 
http://www.cnblogs.com/smarterplanet/p/4088479.html

這個,都很好,不過因為依賴了資料庫,配置比較多,對於初學者來說,搭起來一個最最簡單的環境才是最重要的,擼要一步一步走嘛(如果對spring不是特別熟,強烈不建議看官方的tutorial,槽點太多,例如靜態JS庫的引用方式,web.xml的使用方式,Spring的配置方式,我反正下下來就驚呆了,第一次看到用java程式碼配spring) 

基本需求:
使用者A希望授權網站B能獲取自己在網站appDemo的一個資源,資源的地址是 
http://localhost:8080/appDemo/resource/getUserInfo 

使用的框架及版本:
spring-webmvc 3.2.8spring-security-web 3.2.6spring-security-oauth2 2.0.7 (這是到2015.7為止的最新版本,和1.0有些小區別,我也在這上面卡了一段時間)
Pom檔案見附件整個專案原始碼。 


準備材料(附件都已經包括):
搭建一個springMVC+springSecurity的最簡單環境,並且自定義一個login.jsp寫一個controller和Jsp,充當使用者的受保護資源寫兩個jsp作為scope選擇確認頁面

我們要做的
僅僅是配置spring security的配置檔案就可以了~一點程式碼都不用寫,資料庫也不用連。 

我會從client資訊開始,把整個配置檔案串起來,最後我會講appDemo使用的方法,和以下的配置聯絡起來 

網站B在網站appDemo的"使用者"(注意這裡和使用者A沒半毛錢關係)資訊,即client_id和client_secret配置: Xml程式碼  收藏程式碼
  1. <
    authentication-manager id="clientAuthenticationManager">  
  2.         <authentication-provider user-service-ref="oauth2ClientDetailsUserService" />  
  3.     </authentication-manager>  
  4.     <beans:bean id="oauth2ClientDetailsUserService"  
  5.     class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">  
  6.         <beans:constructor-arg ref="clientDetailsService" />  
  7.     </beans:bean>  
  8. <oauth2:client-details-service id="clientDetailsService">  
  9.         <oauth2:client client-id="m1"  
  10.             authorized-grant-types="password,authorization_code,refresh_token,implicit"  
  11.             secret="s1" scope="read,write,trust" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"  
  12.             resource-ids="pic-resource" />  
  13.     </oauth2:client-details-service>  

注意名稱空間,可以看到client配置和spring security傳統的使用者配置是非常像的。 
這裡配置了網站B在appDemo中的client_id,client_secret,scope,許可權和授權型別,資源ID,那這個資源ID是個啥呢? 
資源filter配置: Xml程式碼  收藏程式碼
  1. <oauth2:resource-server id="picResourceServer"  
  2.         resource-id="pic-resource" token-services-ref="tokenServices" />  

配置這個,除了資源定位(id),還為了給我們的資源加上一個自定義的OAuth過濾器,這個過濾器主要是為了網站B在訪問資源的時候驗證Access Token。然後出現了兩個分支: 
1.配token service 
2.配資源 
先講Token配置: Xml程式碼  收藏程式碼
  1. <beans:bean id="tokenServices"  
  2.         class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">  
  3.         <beans:property name="tokenStore" ref="tokenStore" />  
  4.         <beans:property name="supportRefreshToken" value="true" />  
  5.         <beans:property name="clientDetailsService" ref="clientDetailsService" />  
  6.     </beans:bean>  
  7.     <beans:bean id="tokenStore"  
  8.         class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore">  
  9.     </beans:bean>  

我們把Token存在記憶體裡,擺脫資料庫依賴。想象一下,為了生成和client相關的token,肯定需要把上面提到的ClientService配置進去 

資源和資源的保護 Xml程式碼  收藏程式碼
  1. <http pattern="/resource/**" create-session="never"  
  2.         entry-point-ref="oauth2AuthenticationEntryPoint"  
  3.         access-decision-manager-ref="oauth2AccessDecisionManager">  
  4.         <anonymous enabled="false" />  
  5.         <intercept-url pattern="/resource/**" access="ROLE_USER,SCOPE_READ" />  
  6.         <custom-filter ref="picResourceServer" before="PRE_AUTH_FILTER" />  
  7.         <access-denied-handler ref="oauthAccessDeniedHandler" />  
  8.     </http>  

這是spring security的傳統配置了,除了我們剛才提到的資源filter,還配置了認證失敗、授權失敗的處理,和判斷是否可訪問的"access decision manager" 
認證失敗,授權失敗 Xml程式碼  收藏程式碼
  1. <beans:bean id="oauth2AuthenticationEntryPoint"  
  2.         class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint" />  
  3.     <beans:bean id="oauthAccessDeniedHandler"  
  4.         class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />  

這個沒什麼好解釋的了,其實作為demo也可以不配,畢竟我們應該會一路按能跑通的先跑。 
access decision manager Xml程式碼  收藏程式碼
  1. <beans:bean id="oauth2AccessDecisionManager"  
  2.         class="org.springframework.security.access.vote.UnanimousBased">  
  3.         <beans:constructor-arg>  
  4.             <beans:list>  
  5.                 <beans:bean  
  6.                     class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />  
  7.                 <beans:bean class="org.springframework.security.access.vote.RoleVoter" />  
  8.                 <beans:bean  
  9.                     class="org.springframework.security.access.vote.AuthenticatedVoter" />  
  10.             </beans:list>  
  11.         </beans:constructor-arg>  
  12.     </beans:bean>  

也是傳統的配置方法了,多了個oauth2裡面特有的scope投票機制。 

好,到現在為止,OAuth2 Server所需要的所有龍珠都已經集齊,接下來就可以召喚神龍了 
出來吧!神龍 Xml程式碼  收藏程式碼
  1. <oauth2:authorization-server  
  2.         client-details-service-ref="clientDetailsService" token-services-ref="tokenServices"  
  3.         user-approval-handler-ref="oauthUserApprovalHandler"  
  4.         user-approval-page="oauth_approval" error-page="oauth_error">  
  5.         <oauth2:authorization-code />  
  6.         <oauth2:implicit />  
  7.         <oauth2:refresh-token />  
  8.         <oauth2:client-credentials />  
  9.         <oauth2:password />  
  10.     </oauth2:authorization-server>  
  11.     <beans:bean id="oauthUserApprovalHandler"  
  12.         class="org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler" />  


還差兩步: 
1.網站B來申請Token時候的認證和許可權設定: 
Xml程式碼  收藏程式碼
  1. <http pattern="/oauth/token" create-session="stateless"  
  2.         authentication-manager-ref="clientAuthenticationManager"  
  3.         entry-point-ref="oauth2AuthenticationEntryPoint">  
  4.         <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />  
  5.         <anonymous enabled="false" />  
  6.         <http-basic entry-point-ref="oauth2AuthenticationEntryPoint" />  
  7.         <custom-filter ref="clientCredentialsTokenEndpointFilter"  
  8.             before="BASIC_AUTH_FILTER" />  
  9.         <access-denied-handler ref="oauthAccessDeniedHandler" />  
  10.     </http>  
  11.     <beans:bean id="clientCredentialsTokenEndpointFilter"  
  12.         class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">  
  13.         <beans:property name="authenticationManager" ref="clientAuthenticationManager" />  
  14.     </beans:bean>  


2.作為屌絲使用者A,認證放在配置最後了(也應該放在前面那個http的後面,因為這裡有個全域性匹配了) 
Xml程式碼  收藏程式碼
  1. <http access-denied-page="/login.jsp?error=true"  
  2.         authentication-manager-ref="authenticationManager">  
  3.         <intercept-url pattern="/oauth/**" access="ROLE_USER" />  
  4.         <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />  
  5.         <form-login login-page="/login.jsp"  
  6.             authentication-failure-url="/login.jsp?error=true"  
  7.             default-target-url="/index.jsp" />  
  8.         <anonymous />  
  9.     </http>  
  10.     <authentication-manager alias="authenticationManager">  
  11.         <authentication-provider>  
  12.             <user-service id="userService">  
  13.                 <user name="admin" password="admin" authorities="ROLE_USER" />  
  14.             </user-service>  
  15.         </authentication-provider>  
  16.     </authentication-manager>  


寫到這裡,我默默預覽了一下,估計群眾們看到這句話大都是拖滾軸下來的。 

不過配置真的挺長,不花篇幅真講不清楚。 

最後把大致流程和配置關聯一下: 

  • *.使用者要授權網站B獲取appDemo資源
  • 1.網站B把使用者跳轉到appDemo/oauth/authorize?client_id=m1&redirect_uri=http%3a%2f%2flocalhost%3a8080%2f&response_type=code&scope=read
    Spring Security Oauth2有一個controller:AuthorizationEndpoint處理這個請求,這個是不用配置的。 但是在controller處理之前,appDemo發現,我擦嘞,使用者還沒登入啊(見屌絲使用者A認證配置)!於是先跳轉到登入介面讓使用者登入。 
  • 2.使用者登入成功後,跳轉到了scope選擇確認頁面(見出現吧!神龍)。
  • 3.appDemo生成了Authorization Code並跳轉回網站B(其實神龍的authorization-code這種配置方式有其他的配置項,可以選填Authorzation code service)
  • 4.網站B拿到了code,向appDemo請求accessToken(appDemo/oauth/token?code=g6hW13&client_id=m1&client_secret=s1&grant_type=authorization_code&redirect_uri=http%3a%2f%2flocalhost%3a8080%2f)網站B的client認證配置起作用了,AccessDecisionManager起作用了,資源資訊起作用了,Token生成也起作用了。
  • 5.最後網站B通過access token訪問資源,資源和資源的保護配置起作用了。


具體的使用流程在appDemo的index頁面有步驟。 

原始碼見 https://github.com/wwwcomy/appDemo/tree/OAuth2

完。