oauth簡單使用

1、oauth原理參考

  理解OAuth 2.0html

2、本例中採用受權碼模式

  

  大體流程git

  (A)用戶訪問客戶端,後者將前者導向認證服務器。
  (B)用戶選擇是否給予客戶端受權。
  (C)假設用戶給予受權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個受權碼。
  (D)客戶端收到受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見。
  (E)認證服務器覈對了受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。github

  參數含義web

  response_type:表示受權類型,必選項,此處的值固定爲"code"
  client_id:表示客戶端的ID,必選項
  redirect_uri:表示重定向URI,可選項
  scope:表示申請的權限範圍,可選項,本例中無
  state:表示客戶端的當前狀態,能夠指定任意值,認證服務器會原封不動地返回這個值,本例中無spring

3、項目中依賴oauth相關jar

<!-- oauth -->
<dependency>
    <groupId>org.apache.oltu.oauth2</groupId>
    <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
    <version>${oauth2-version}</version>
</dependency>
<dependency>
    <groupId>org.apache.oltu.oauth2</groupId>
    <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
    <version>${oauth2-version}</version>
</dependency>
<dependency>
    <groupId>org.apache.oltu.oauth2</groupId>
    <artifactId>org.apache.oltu.oauth2.client</artifactId>
    <version>${oauth2-version}</version>
</dependency>

4、獲取受權碼

/**
 * 獲取受權碼-服務端
 *
 * @param request
 * @return
 * @throws OAuthProblemException
 * @throws OAuthSystemException
 */
@RequestMapping(value = "/authorize", method = RequestMethod.GET)
@ResponseBody
public Object authorize(HttpServletRequest request) throws URISyntaxException, OAuthProblemException, OAuthSystemException {
    try {
        // 構建OAuth受權請求
        OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);

        // 1.獲取OAuth客戶端id
        String clientId = oauthRequest.getClientId();
        // 校驗客戶端id是否正確
        LightUserResult lightUserResult = userApi.queryUserByClientId(clientId);
        if (null == lightUserResult) {
            OAuthResponse response =
                    OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                            .setError(OAuthError.TokenResponse.INVALID_CLIENT)
                            .setErrorDescription("無效的客戶端ID")
                            .buildJSONMessage();
            return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
        }

        // 2.生成受權碼
        String authCode = null;
        String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);
        // ResponseType僅支持CODE和TOKEN
        if (responseType.equals(ResponseType.CODE.toString())) {
            OAuthIssuerImpl oAuthIssuer = new OAuthIssuerImpl(new MD5Generator());
            authCode = oAuthIssuer.authorizationCode();
            // 存入緩存中authCode-username
            RedisUtil.getRedis().set(authCode, lightUserResult.getUserName());
        }
        return new ResponseEntity(authCode, HttpStatus.OK);
    } catch (Exception e) {
        return new ResponseEntity("內部錯誤", HttpStatus.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
    }
}

5、根據受權碼獲取token

/**
 * 獲取訪問令牌
 *
 * @param request
 * @return
 * @throws OAuthProblemException
 * @throws OAuthSystemException
 */
@RequestMapping(value = "accessToken", method = RequestMethod.POST)
@ResponseBody
public Object accessToken(HttpServletRequest request) throws OAuthProblemException, OAuthSystemException {
    try {
        // 構建OAuth請求
        OAuthTokenRequest tokenRequest = new OAuthTokenRequest(request);

        // 1.獲取OAuth客戶端id
        String clientId = tokenRequest.getClientId();
        // 校驗客戶端id是否正確
        LightUserResult lightUserResult = userApi.queryUserByClientId(clientId);
        if (null == lightUserResult) {
            OAuthResponse oAuthResponse = OAuthResponse
                    .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_CLIENT)
                    .setErrorDescription("無效的客戶端ID")
                    .buildJSONMessage();
            return new ResponseEntity(oAuthResponse.getBody(), HttpStatus.valueOf(oAuthResponse.getResponseStatus()));
        }

        // 2.檢查客戶端安全key是否正確
        if (!lightUserResult.getClientSecret().equals(tokenRequest.getClientSecret())) {
            OAuthResponse oAuthResponse = OAuthResponse
                    .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
                    .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
                    .setErrorDescription("客戶端安全key認證不經過")
                    .buildJSONMessage();
            return new ResponseEntity<>(oAuthResponse.getBody(), HttpStatus.valueOf(oAuthResponse.getResponseStatus()));
        }

        // 3.檢查受權碼是否正確
        String authCode = tokenRequest.getParam(OAuth.OAUTH_CODE);
        // 檢查驗證類型,此處只檢查AUTHORIZATION_CODE類型,其餘的還有password或REFRESH_TOKEN
        if (!tokenRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.AUTHORIZATION_CODE.toString())) {
            if (null == RedisUtil.getRedis().get(authCode)) {
                OAuthResponse response = OAuthASResponse
                        .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                        .setError(OAuthError.TokenResponse.INVALID_GRANT)
                        .setErrorDescription("受權碼錯誤")
                        .buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

            }
        }

        // 4.生成訪問令牌Access Token
        OAuthIssuer oAuthIssuer = new OAuthIssuerImpl(new MD5Generator());
        final String accessToken = oAuthIssuer.accessToken();
        // 將訪問令牌加入緩存:accessToken-username
        RedisUtil.getRedis().set(accessToken, lightUserResult.getUserName());

        // 5.生成OAuth響應
        OAuthResponse response = OAuthASResponse
                .tokenResponse(HttpServletResponse.SC_OK)
                .setAccessToken(accessToken)
                .setExpiresIn(expiresIn)
                .buildJSONMessage();

        return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity("內部錯誤", HttpStatus.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
    }

}

 6、簡單測試

@RequestMapping("authority")
@ResponseBody
public JSONObject authority() throws OAuthSystemException, OAuthProblemException {
    JSONObject result = new JSONObject();
    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
    OAuthClientRequest codeTokenRequest = OAuthClientRequest
            .authorizationLocation("http://127.0.0.1:8080/auth-web/oauth/authorize")
            .setResponseType(ResponseType.CODE.toString())
            .setClientId("c1ebe466-1cdc-4bd3-ab69-77c3561b9dee")
            .buildQueryMessage();
    //獲取 code
    OAuthResourceResponse codeResponse = oAuthClient.resource(
            codeTokenRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);
    if(codeResponse.getResponseCode() != HttpServletResponse.SC_OK) {
        result.put("code", codeResponse.getResponseCode());
        result.put("msg", codeResponse.getBody());
    } else {
        String authCode = codeResponse.getBody();
        OAuthClientRequest accessTokenRequest = OAuthClientRequest
                .tokenLocation("http://127.0.0.1:8080/auth-web/oauth/accessToken")
                .setGrantType(GrantType.AUTHORIZATION_CODE)
                .setClientId("c1ebe466-1cdc-4bd3-ab69-77c3561b9dee").setClientSecret("d8346ea2-6017-43ed-ad68-19c0f971738b")
                .setCode(authCode).setRedirectURI("http://127.0.0.1:8080/auth-web/")
                .buildQueryMessage();
        //獲取access token
        OAuthAccessTokenResponse tokenResponse =
                oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);
        if(tokenResponse.getResponseCode() != HttpServletResponse.SC_OK) {
            result.put("code", tokenResponse.getResponseCode());
            result.put("msg", tokenResponse.getBody());
            return result;
        } else {
            //驗證token
            OAuthClientRequest validateRequest =
                    new OAuthBearerClientRequest("http://127.0.0.1:8080/auth-web/oauth/validate")
                            .setAccessToken(tokenResponse.getAccessToken()).buildQueryMessage();
            OAuthResourceResponse validateResponse = oAuthClient.resource(
                    validateRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);
            if(validateResponse.getResponseCode() != HttpServletResponse.SC_OK) {
                result.put("code", validateResponse.getResponseCode());
                result.put("msg", validateResponse.getBody());
            } else {
                JSONObject body = JSON.parseObject(validateResponse.getBody());
                result.put("code", body.getString("code"));
                result.put("msg", body.getString("msg"));
            }
        }
    }
    return result;
}
public static ResponseEntity oauthValidate(HttpServletRequest request) throws OAuthProblemException, OAuthSystemException {

    // 構建OAuth資源請求
    OAuthAccessResourceRequest resourceRequest = new OAuthAccessResourceRequest(request, ParameterStyle.QUERY);
    // 獲取訪問令牌access Token
    String accessToken = resourceRequest.getAccessToken();
    // 驗證訪問令牌
    if (null == RedisUtil.getRedis().get(accessToken)) {
        // 若是不存在或過時了,返回未驗證錯誤,需從新驗證
        OAuthResponse response = OAuthRSResponse
                .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
                .setError(OAuthError.ResourceResponse.INVALID_TOKEN)
                .setErrorDescription("訪問令牌不存在或已過時,請從新驗證")
                .buildJSONMessage();
        return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
    }
    return new ResponseEntity("驗證成功", HttpStatus.valueOf(HttpServletResponse.SC_OK));
}

7、項目地址

  oauth認證demo下載apache

相關文章
相關標籤/搜索