spring oauth2 ,spring security整合oauth2.0 JdbcTokenStore實現 解決url-pattern .do .action

參考如下兩個文章:html

http://www.cnblogs.com/0201zcr/p/5328847.htmlweb

http://wwwcomy.iteye.com/blog/2230265spring

web.xml 注意這裏的<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>   <url-pattern>/*</url-pattern>  而<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <url-pattern>*.action</url-pattern>會致使org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter構造器裏面的/oauth/token被security攔截,而spring mvc卻沒有攔截數據庫

    <!-- SpringSecurity必須的filter start-->  
    <filter>  
        <filter-name>springSecurityFilterChain</filter-name>  
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    </filter>    
    <filter-mapping>  
        <filter-name>springSecurityFilterChain</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>
    <!-- SpringSecurity必須的filter end-->
                 
    <servlet>        
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>            
            <param-value>
                classpath:applicationContextMvc.xml
            </param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>    
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    <!--  /oauth/token 是oauth2登錄驗證請求的url     用於獲取access_token  ,默認的生存時間是43200秒,即12小時-->
    <http pattern="/oauth/token.action" create-session="stateless" authentication-manager-ref="clientAuthenticationManager">
          <intercept-url pattern="/oauth/token.action" access="IS_AUTHENTICATED_FULLY" />      <!--  能夠訪問的角色名稱,若是須要攔截,須要實現UserDetails接口,實現getAuthorities()方法-->
        <anonymous enabled="false" />
        <http-basic entry-point-ref="oauth2AuthenticationEntryPoint" />
        <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
        <access-denied-handler ref="oauth2AccessDeniedHandler" />
    </http>

這個authentication-manager 是OAUTH的,還須要另外一個spring security ,若是已經在使用spring security 那麼只須要配置這一個.ClientDetailsUserDetailsService 實現了spring security的UserDetailsService,在ClientDetailsUserDetailsService json

的loadUserByUsername並非驗證咱們用戶的帳號密碼,驗證用戶的帳號密碼在spring security裏面已經本身處理了,這裏的loadUserByUsername是驗證咱們的客戶端也就是第三方的網址,或者APP,是否有權限訪問咱們的接口.例如這裏咱們的第三方APP用戶名爲mobile_1,密碼爲secret_1,能夠配置多個第三方APP服務器

        <!-- 驗證的權限控制 -->
    <authentication-manager id="clientAuthenticationManager">
        <authentication-provider user-service-ref="oauth2ClientDetailsUserService"  />
    </authentication-manager>
    
    
    <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" authorities="ROLE_CLIENT,ROLE_TRUSTED_CLIENT"  resource-ids="mobile-resource" />
    </oauth2:client-details-service>
    <beans:bean id="oauth2ClientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
        <beans:constructor-arg ref="clientDetailsService" /> 
    </beans:bean>

spring security 的authentication-manager  , daoAuthenticationProvider須要本身實現,這裏就不貼出來了session

      <!-- 權限管理者 -->
       <authentication-manager alias="myAuthenticationManager">
               <!-- 權限提供者 -->
               <authentication-provider ref="daoAuthenticationProvider" />
       </authentication-manager>
       
       <beans:bean id="daoAuthenticationProvider" class="com.thesys.common.security.provider.MyDaoAuthenticationProvider">
              <beans:property name="userDetailsService" ref="securityService" /> 
              <beans:property name="PasswordEncoder" ref="md5PasswordEncoder" />
        </beans:bean> 

複製org.springframework.security.oauth2.provider.token.DefaultTokenServices 內容新建類MyTokenService  本身重寫 private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken)這個方法,實現本身的TOKEN生成方式mvc

              <!-- for spring oauth2 -->
    <!--token在服務器存儲的方式    InMemoryTokenStore :保存在內存     ;JdbcTokenStore : 保存在數據庫中 -->
    <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:bean id="tokenServices" class="com.thesys.common.security.oauth.MyTokenService" > 
            <beans:property name="tokenStore" ref="tokenStore"></beans:property> 
            <beans:property name="supportRefreshToken" value="true"/> 
            <beans:property name="clientDetailsService" ref="clientDetailsService" />  
    </beans: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>

這裏解決.do .action的攔截問題, <beans:constructor-arg value="/oauth/token.action" /> 把默認的/oauth/token 改爲/oauth/token.action 就能夠解決.do或者.action 的攔截問題app

 <beans:bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
        <beans:property name="authenticationManager" ref="clientAuthenticationManager" />
        <beans:constructor-arg value="/oauth/token.action" />
    </beans:bean>  
 <intercept-url pattern="/admin**" access="IS_AUTHENTICATED_FULLY" /> 由於沒有項目沒有角色的設置,只要登陸了就能夠訪問,因此不設置角色驗證
   <!--指定spring要保護的資源,若是沒有這個,訪問控制的時候會說沒有Authentication object:-->
    <oauth2:resource-server id="mobileResourceServer" resource-id="mobile-resource" token-services-ref="tokenServices" />
    
    <http pattern="/json**" create-session="never" entry-point-ref="oauth2AuthenticationEntryPoint" access-decision-manager-ref="oauth2AccessDecisionManager">
        <anonymous enabled="false" />
          <intercept-url pattern="/json**" access="IS_AUTHENTICATED_FULLY" /><!--  -->
        <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="IS_AUTHENTICATED_FULLY" /> <!-- -->
        <custom-filter ref="mobileResourceServer" before="PRE_AUTH_FILTER" />
        <access-denied-handler ref="oauth2AccessDeniedHandler" />
    </http>

由於沒有設置必須爲POST 提交,因此不管GET POST 提交如下請求會返回access_tokenless

http://localhost:8028/oauth/token.action?client_id=mobile_1&client_secret=secret_1&grant_type=password&username=test&password=1
  1. {
  2.    "access_token": "6cd40d26561c4ac89e447dd5214c7033",
  3.    "token_type": "bearer",
  4.    "refresh_token": "459f7555-e733-43c9-8ab8-016b15a61427",
  5.    "expires_in": 43199,
  6.    "scope": "read trust write"
  7. }

刷新access_token

/oauth/token.action?client_id=&client_secret=&grant_type=refresh_token&refresh_token=459f7555-e733-43c9-8ab8-016b15a61427

{
"access_token": "859f08ec-7552-45b2-bb54-50328e462646",
"token_type": "bearer",
"refresh_token": "26bef8b9-2521-4efd-a81b-1e2873866c8f",
"expires_in": 2591999,
"scope": "read trust write"
}




 

 

 

而後帶着access_token訪問,就能夠成功訪問

http://localhost:8028/admin.action?access_token=52d33d7d81ee4a388d79bf00387b1325

沒有access_token訪問的話,會返回(注意看這裏是XML方式返回,由於請求頭爲空,spring返回默認第一個,若是須要json,那麼請在請求頭加上accept:application/json)

http://localhost:8028/admin.action
  1. <oauth>
  2. <error_description>An Authentication object was not found in the SecurityContext</error_description>
  3. <error>unauthorized</error>
  4. </oauth>

 數據庫存儲方式

    <!--token在服務器存儲的方式    InMemoryTokenStore :保存在內存     ;JdbcTokenStore : 保存在數據庫中 
    <beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore" />-->
    <beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore" >

按照規範建兩個表,由於須要訪問的第三方很少,我只須要持久化access_token因此沒有創建oauth_client_details,oauth_code

Drop table  if exists oauth_access_token;
create table oauth_access_token (
  create_time timestamp default now(),
  token_id VARCHAR(255),
  token BLOB,
  authentication_id VARCHAR(255),
  user_name VARCHAR(255),
  client_id VARCHAR(255),
  authentication BLOB,
  refresh_token VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Drop table  if exists oauth_refresh_token;
create table oauth_refresh_token (
  create_time timestamp default now(),
  token_id VARCHAR(255),
  token BLOB,
  authentication BLOB
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
相關文章
相關標籤/搜索