Spring security oauth2最簡單入門環境搭建--二、乾貨
阿新 • • 發佈:2019-02-14
轉載自: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程式碼
-
<
- <authentication-provider user-service-ref="oauth2ClientDetailsUserService" />
- </authentication-manager>
- <beans:bean id="oauth2ClientDetailsUserService"
- class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
- <beans:constructor-arg ref="clientDetailsService" />
- </beans:bean>
- <oauth2:client-details-service id="clientDetailsService">
- <oauth2:client client-id="m1"
- authorized-grant-types="password,authorization_code,refresh_token,implicit"
- secret="s1" scope="read,write,trust" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
- resource-ids="pic-resource" />
- </oauth2:client-details-service>
注意名稱空間,可以看到client配置和spring security傳統的使用者配置是非常像的。
這裡配置了網站B在appDemo中的client_id,client_secret,scope,許可權和授權型別,資源ID,那這個資源ID是個啥呢?
資源filter配置: Xml程式碼
- <oauth2:resource-server id="picResourceServer"
- resource-id="pic-resource" token-services-ref="tokenServices" />
配置這個,除了資源定位(id),還為了給我們的資源加上一個自定義的OAuth過濾器,這個過濾器主要是為了網站B在訪問資源的時候驗證Access Token。然後出現了兩個分支:
1.配token service
2.配資源
先講Token配置: Xml程式碼
- <beans:bean id="tokenServices"
- class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
- <beans:property name="tokenStore" ref="tokenStore" />
- <beans:property name="supportRefreshToken" value="true" />
- <beans:property name="clientDetailsService" ref="clientDetailsService" />
- </beans:bean>
- <beans:bean id="tokenStore"
- class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore">
- </beans:bean>
我們把Token存在記憶體裡,擺脫資料庫依賴。想象一下,為了生成和client相關的token,肯定需要把上面提到的ClientService配置進去
資源和資源的保護 Xml程式碼
- <http pattern="/resource/**" create-session="never"
- entry-point-ref="oauth2AuthenticationEntryPoint"
- access-decision-manager-ref="oauth2AccessDecisionManager">
- <anonymous enabled="false" />
- <intercept-url pattern="/resource/**" access="ROLE_USER,SCOPE_READ" />
- <custom-filter ref="picResourceServer" before="PRE_AUTH_FILTER" />
- <access-denied-handler ref="oauthAccessDeniedHandler" />
- </http>
這是spring security的傳統配置了,除了我們剛才提到的資源filter,還配置了認證失敗、授權失敗的處理,和判斷是否可訪問的"access decision manager"
認證失敗,授權失敗 Xml程式碼
- <beans:bean id="oauth2AuthenticationEntryPoint"
- class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint" />
- <beans:bean id="oauthAccessDeniedHandler"
- class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
這個沒什麼好解釋的了,其實作為demo也可以不配,畢竟我們應該會一路按能跑通的先跑。
access decision manager Xml程式碼
- <beans:bean id="oauth2AccessDecisionManager"
- class="org.springframework.security.access.vote.UnanimousBased">
- <beans:constructor-arg>
- <beans:list>
- <beans:bean
- class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
- <beans:bean class="org.springframework.security.access.vote.RoleVoter" />
- <beans:bean
- class="org.springframework.security.access.vote.AuthenticatedVoter" />
- </beans:list>
- </beans:constructor-arg>
- </beans:bean>
也是傳統的配置方法了,多了個oauth2裡面特有的scope投票機制。
好,到現在為止,OAuth2 Server所需要的所有龍珠都已經集齊,接下來就可以召喚神龍了
出來吧!神龍 Xml程式碼
- <oauth2:authorization-server
- client-details-service-ref="clientDetailsService" token-services-ref="tokenServices"
- user-approval-handler-ref="oauthUserApprovalHandler"
- user-approval-page="oauth_approval" error-page="oauth_error">
- <oauth2:authorization-code />
- <oauth2:implicit />
- <oauth2:refresh-token />
- <oauth2:client-credentials />
- <oauth2:password />
- </oauth2:authorization-server>
- <beans:bean id="oauthUserApprovalHandler"
- class="org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler" />
還差兩步:
1.網站B來申請Token時候的認證和許可權設定:
Xml程式碼
- <http pattern="/oauth/token" create-session="stateless"
- authentication-manager-ref="clientAuthenticationManager"
- entry-point-ref="oauth2AuthenticationEntryPoint">
- <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
- <anonymous enabled="false" />
- <http-basic entry-point-ref="oauth2AuthenticationEntryPoint" />
- <custom-filter ref="clientCredentialsTokenEndpointFilter"
- before="BASIC_AUTH_FILTER" />
- <access-denied-handler ref="oauthAccessDeniedHandler" />
- </http>
- <beans:bean id="clientCredentialsTokenEndpointFilter"
- class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
- <beans:property name="authenticationManager" ref="clientAuthenticationManager" />
- </beans:bean>
2.作為屌絲使用者A,認證放在配置最後了(也應該放在前面那個http的後面,因為這裡有個全域性匹配了)
Xml程式碼
- <http access-denied-page="/login.jsp?error=true"
- authentication-manager-ref="authenticationManager">
- <intercept-url pattern="/oauth/**" access="ROLE_USER" />
- <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
- <form-login login-page="/login.jsp"
- authentication-failure-url="/login.jsp?error=true"
- default-target-url="/index.jsp" />
- <anonymous />
- </http>
- <authentication-manager alias="authenticationManager">
- <authentication-provider>
- <user-service id="userService">
- <user name="admin" password="admin" authorities="ROLE_USER" />
- </user-service>
- </authentication-provider>
- </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
完。