如今加最後同樣,就是oauth2,如今不少網站都有對應的移動版本,那麼移動端訪問服務端的服務怎麼控制權限,我知道的主要是兩種方法,第一是模擬瀏覽器,訪問服務的時候會生成session,以後在移動端緩存cookie,每次網絡請求都把cookie加上,還有一種就是經過oauth2,登陸以後生成一個憑證,每次請求時攜帶憑證,固然oauth2更多的是爲第三方應用提供訪問本身服務的權限。html
oauth2的配置,能夠純配置文件打造,相比較前面的那些,能夠說是最簡單也是最複雜的,簡單是由於引入jar包配置一個xml就能夠,複雜是說這個僅有的xml須要寫的東西不少理解起來也要費勁。spring
關於Oauth2的整合,很大程度上參考了這位仁兄的文章:http://blog.csdn.net/monkeyking1987/article/details/16828059。數據庫
1. pom.xmljson
首先導入oauth2的包:瀏覽器
<properties> …… <spring-security-oauth2.version>2.0.2.RELEASE</spring-security-oauth2.version> </properties> <dependencies> …… <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>${spring-security-oauth2.version}</version> </dependency> …… </dependencies>
2. applicationContext-security.xml緩存
oauth2是security的一部分,配置也有關聯,就再也不單建文件,首先要在最前面加一些schema:服務器
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth2="http://www.springframework.org/schema/security/oauth2" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
其實就是加了一個oauth2的命名。cookie
在這個文件的開始,也就是以前配置的攔截鏈的http標籤前面並列一個http標籤:網絡
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="oauth2AuthenticationManager" 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="oauth2AccessDeniedHandler"/> </http>
這個標籤處理/oauth/token的網絡請求,這是oauth2的登陸驗證請求,那麼登陸須要什麼,首先,和Spring Security同樣,須要一個認證管理器,Spring Oauth2須要兩個認證管理器,第一個就是以前Spring中配置的那一個,用來驗證用戶名密碼的,還有一個是用來區分客戶端用戶的,給它起個名字叫oauth2AuthenticationManager:session
<oauth2:client-details-service id="clientDetailsService"> <oauth2:client client-id="mobile_1" authorized-grant-types="password,authorization_code,refresh_token,implicit" secret="secret_1"scope="read,write,trust" /> </oauth2:client-details-service> <beans:bean id="oauth2ClientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService"> <beans:constructor-arg ref="clientDetailsService"/> </beans:bean> <authentication-manager id="oauth2AuthenticationManager"> <authentication-provider user-service-ref="oauth2ClientDetailsUserService"/> </authentication-manager>
這兒設置了一種客戶端,id叫作mobile_1,secret叫作secret_1,針對read、write和trust幾個域有效。這幾個域會在訪問控制中被用到。
當登陸成功以後會獲得一個token,再次訪問的時候須要攜帶這個token,spring-oauth2根據這個token來作認證,那麼spring-oauth2必須先存一份token和用戶關係的對應,由於不用session了,這就至關於session,那麼這個token在服務器中怎麼存,有兩種主要的存儲方式,一是建立數據表,把token存到數據庫裏,我如今追求簡單可用,採用第二種方式,直接存到內存裏。下面配置一個管理token的service:
<beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"/> <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:bean>
下面配置4個基本的bean:分別處理訪問成功、訪問拒絕、認證點和訪問控制:
<beans:bean id="oauth2AuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"/> <beans:bean id="oauth2AccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/> <beans:bean id="oauthUserApprovalHandler" class="org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler"/> <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的server所能支持的請求類型:
<oauth2:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices" user-approval-handler-ref="oauthUserApprovalHandler" > <oauth2:authorization-code /> <oauth2:implicit /> <oauth2:refresh-token /> <oauth2:client-credentials /> <oauth2:password /> </oauth2:authorization-server>
好比說,若是配置本服務器不支持刷新token,那麼就:
<oauth2:refresh-token disabled="true" />
咱們的請求裏,要把驗證類型、用戶名密碼都做爲表單參數提交,這就須要配置下面的filter:
<beans:bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter"> <beans:property name="authenticationManager" ref="oauth2AuthenticationManager"/> </beans:bean>
下面定義一種資源,指定spring要保護的資源,若是沒有這個,訪問控制的時候會說沒有Authentication object:
<oauth2:resource-server id="mobileResourceServer" resource-id="mobile-resource" token-services-ref="tokenServices" />
好了,到此爲止基本配置就都有了,下面就看訪問控制的配置:在前面的攔截鏈上,已經爲登陸驗證配了一個/auth/token,在這個標籤下面添加對/json和/admin這兩個路徑的控制(這裏沒有再寫這兩個訪問的controller,依舊用前面幾篇文章中寫好的):
<http pattern="/json**" create-session="never" entry-point-ref="oauth2AuthenticationEntryPoint" access-decision-manager-ref="oauth2AccessDecisionManager"> <anonymous enabled="false" /> <intercept-url pattern="/json**" access="ROLE_USER" /> <custom-filter ref="mobileResourceServer" before="PRE_AUTH_FILTER" /> <access-denied-handler ref="oauth2AccessDeniedHandler" /> </http> <http pattern="/admin**" create-session="never" entry-point-ref="oauth2AuthenticationEntryPoint" access-decision-manager-ref="oauth2AccessDecisionManager"> <anonymous enabled="false" /> <intercept-url pattern="/admin**" access="ROLE_ADMIN,SCOPE_READ" /> <custom-filter ref="mobileResourceServer" before="PRE_AUTH_FILTER" /> <access-denied-handler ref="oauth2AccessDeniedHandler" /> </http>
咱們用oauth2AccessDecisionManager來作決策,這個地方須要注意,spring-security裏面配置access="ROLE_USER,ROLE_ADMIN"是說user和admin均可以訪問,是一個「或」的關係,可是這裏是「與」的關係,好比第二個,須要ROLE_ADMIN而且當前的scope包含read才能夠,不然就沒有權限。認證失敗會返回一段xml,這個能夠自定義handler來修改,暫且按下不表。
源碼下載。
ps:使用方法:用戶名密碼前面spring-security中已經建立了用戶,驗證身份時訪問:
http://localhost:8080/demo4ssh-security-oauth2/oauth/token?client_id=mobile_1&client_secret=secret_1&grant_type=password&username=zhangsan&password=123456
這時候會返回一個access_token:
{"access_token":"4219a91f-45d5-4a07-9e8e-3acbadd0c23e","token_type":"bearer","refresh_token":"d41df9fd-3d36-4a20-b0b7-1a1883c7439d","expires_in":43199,"scope":"read write trust"}
這以後再拿着這個access_token去訪問資源:
http://localhost:8080/demo4ssh-security-oauth2/admin?access_token=4219a91f-45d5-4a07-9e8e-3acbadd0c23e