<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                > 如果不理解oauth協議的推薦閱讀 阮一峰的[理解OAuth 2.0](http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html) 當然,我們也要簡單介紹下oauth的運行流程: ``` +--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | | | Owner | | |<-(B)-- Authorization Grant ---| | | | +---------------+ | | | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client | | Server | | |<-(D)----- Access Token -------| | | | +---------------+ | | | | +---------------+ | |--(E)----- Access Token ------>| Resource | | | | Server | | |<-(F)--- Protected Resource ---| | +--------+ +---------------+ ``` 運行流程如下圖,摘自RFC 6749。 - (A)用戶打開客戶端以后,客戶端要求用戶給予授權。 - (B)用戶同意給予客戶端授權。 - (C)客戶端使用上一步獲得的授權,向認證服務器申請令牌。 - (D)認證服務器對客戶端進行認證以后,確認無誤,同意發放令牌。 - (E)客戶端使用令牌,向資源服務器申請獲取資源。 - (F)資源服務器確認令牌無誤,同意向客戶端開放資源。 我們是對內的系統,并不需要那么復雜的流程,所以我們看下oauth的授權模式當中的密碼模式: ``` +----------+ | Resource | | Owner | | | +----------+ v | Resource Owner (A) Password Credentials | v +---------+ +---------------+ | |>--(B)---- Resource Owner ------->| | | | Password Credentials | Authorization | | Client | | Server | | |<--(C)---- Access Token ---------<| | | | (w/ Optional Refresh Token) | | +---------+ +---------------+ ``` 這里的流程相對就比較簡單了: (A)用戶向客戶端提供用戶名和密碼。 (B)客戶端將用戶名和密碼發給認證服務器,向后者請求令牌。 (C)認證服務器確認無誤后,向客戶端提供訪問令牌。 現在將簡單的轉換下思路: - `Resource Owner`:資源擁有者,擁有訂單,購物車等數據的人,既用戶 - `Client`:客戶端,瀏覽器 - `Authorization Server`:認證服務器,也就是服務器咯。 在此A、B、C三個流程就變成了: (A)用戶在瀏覽器輸入用戶名和密碼。 (B)瀏覽器將用戶名和密碼發給服務器,向后者請求令牌(token)。 (C)服務器確認無誤后,返回token給用戶。 但是根據標準的流程,并沒有驗證碼之類的容身之地。而`spring security oauth2` 給我們提供的只能是標準的流程,所以我們對代碼進行一些適配,能夠適應我們自己的需求。 ## spring的部分源碼 我們先來看下`spring security oauth2`的部分源碼 首先我們直接進行授權的時候,調用的url大概為:`http://localhost:8080/oauth/token?username=user_1&password=123456&grant_type=password&scope=select&client_id=client_2&client_secret=123456`,那么授權肯定是與該鏈接相關聯的。基于這個猜測,我們去尋找源碼吧。 在`idea`中使用全局搜索,搜索 字符串`"/oauth/token"`(帶著引號),發現了一個類,似乎與這個請求有關 `ClientCredentialsTokenEndpointFilter` ```java public class ClientCredentialsTokenEndpointFilter extends AbstractAuthenticationProcessingFilter { public ClientCredentialsTokenEndpointFilter() { this("/oauth/token"); } } ``` ``` ClientCredentialsTokenEndpointFilter ---> AbstractAuthenticationProcessingFilter ---> GenericFilterBean ---> Filter ``` 發現,這個類是一個 `Filter` 也就是過濾器,通過這個過濾器,過濾請求,那么,我們去看看`doFilter`方法咯,`doFilter` 在 `ClientCredentialsTokenEndpointFilter` 的父類 `AbstractAuthenticationProcessingFilter` 上。 我們看看`AbstractAuthenticationProcessingFilter`: ```java public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; // 如果不是認證的請求,直接下一個filter // 這里是怎么判斷是否是下一個請求呢? // 答:看看url是不是上面ClientCredentialsTokenEndpointFilter 創建時傳過來的url,也就是 /oauth/token if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } Authentication authResult; try { // 調用attemptAuthentication 方法,返回一個 Authentication 的實現類,也就是認證信息,這個實現類非常重要!!! authResult = attemptAuthentication(request, response); // 如果找不到,那就沒了 if (authResult == null) { return; } } // 調用成功的方法 successfulAuthentication(request, response, chain, authResult); } ``` 這里最重要的方法`attemptAuthentication` 生成一個授權信息,能夠返回,則證明登錄已經成功了,所以真正的登錄與這里有關。 我們回到`ClientCredentialsTokenEndpointFilter` 這個實現類里面看看`attemptAuthentication`方法吧 ```java @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { // ======精簡沒啥用的方法======== // 構造一個UsernamePasswordAuthenticationToken UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(clientId, clientSecret); // 調用認證方法進行認證 return this.getAuthenticationManager().authenticate(authRequest); } ``` 我們通過添加斷點可以發現 `this.getAuthenticationManager()` 是一個`ProviderManager` 對象,我們看下 `this.getAuthenticationManager().authenticate()` 里面的 `authenticate` ```java public class ProviderManager{ public Authentication authenticate(Authentication authentication) throws AuthenticationException { Authentication result = null; for (AuthenticationProvider provider : getProviders()) { // 在一堆的provider中尋找到一個合適的授權提供者 if (!provider.supports(toTest)) { continue; } // 由授權提供者進行授權 result = provider.authenticate(authentication); } if (result != null) { return result; } } } ``` 一路追蹤到這里,我們發現,實際上,是通過`provider.supports(toTest)` 尋找一個合適的授權提供者,使用`provider.authenticate(authentication)`就行授權,而`supports` 的依據是通過之前生成的token來判斷是否支持: ```java public boolean supports(Class<?> authentication) { return (UsernamePasswordAuthenticationToken.class .isAssignableFrom(authentication)); } ``` 我們整理下這幾個流程 ``` ClientCredentialsTokenEndpointFilter.doFilter() --> AbstractAuthenticationProcessingFilter.attemptAuthentication() --> ProviderManager.authenticate() --> AuthenticationProvider.supports() --> AuthenticationProvider.authenticate() ``` 我們可以看到這里主要就是干了幾件事情 - 通過filter 確定登錄要過濾的url - 通過filter 確定生成的`AbstractAuthenticationToken` 比如 `UsernamePasswordAuthenticationToken` - 通過生成的`AbstractAuthenticationToken` 確定`AuthenticationProvider` - 通過`AuthenticationProvider` 最后調用 `authenticate()`方法最后進行授權 最后通過`RequestMapping` 返回 ```java @FrameworkEndpoint public class TokenEndpoint extends AbstractEndpoint{ @RequestMapping(value = "/oauth/token", method=RequestMethod.POST) public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException { String clientId = getClientId(principal); ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId); TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient); OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); return getResponse(token); } } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看