oauth2 學習(一)-使用Apache oltu實現oauth2的受權服務器

         最近作oauth2預研,查了至關多的資料java

         由於現有的項目是使用java 語言來實現的,且不打算直接去實現這一整套的標準。所以先去官網(https://oauth.net/code/)看了下現有的java版實現。其實還有其餘的實現沒有收錄進去。git

 

  比較以後發現資料相對較多的是Apache oltu以及 spring sercurity oauth.由於都是開源的,就去把源代碼都clone下來了。我的認爲Oltu相對來講更輕量,也更簡單,是對oauth2的簡單實現。不少後續校驗的事情都須要咱們本身去作,但這也是它靈活的一面。因此一開始,是決定使用Apache 的oltu。參考了楊開濤的博客(OAuth2集成——《跟我學Shiro》)使用oltu實現了一個簡單的認證服務器。        github

 

         一開始是打算寫三個服務的oauthservice,oauthclient,oauthresource,後來爲了省時間直接把客戶端也集成到服務裏面了,交互界面也只是幾個簡單的輸入框。spring

         認證服務主要有幾個接口後端

 

         /login:登陸接口springboot

  /Oauth/authorize:獲取受權碼的接口服務器

  /Oauth/getCode:這個其實就是受權碼接口,只是例子中後端沒有存儲登陸狀態,作了箇中轉app

  /Oauth/ accesstoken:獲取訪問令牌ui

下面來講說每一個接口具體作了什麼事url

  1. 獲取受權碼
    1. 將請求轉換成oltu的認證請求OauthAuthzRequest
    2. 從 OauthAuthzRequest 讀取客戶端信息(clientId,redirectUrl,response_type)
    3. 校驗客戶端信息
    4. 校驗成功後生成訪問令牌
    5. 存儲訪問令牌
    6. 使用oltu的OAuthASResponse構建oauth響應
    7. 在響應中設置好受權碼,state等信息
    8. 重定向到客戶端的redirectUrl
      public Object getCode(HttpServletRequest request) {
      		try {
      			OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
      			OAuthResponse oAuthResponse;
      			String clientId=oauthRequest.getClientId();
      			//校驗client信息
      			if(!oauthClientService.checkClient(clientId))
      			{
      				return ControllerHelper
      						.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST
      								, OAuthError.TokenResponse.INVALID_CLIENT
      								, ErrorConstants.ERROR_CLIENT_MSG);				
      			}
      			//獲取登錄信息
      			//已經登陸校驗內部token信息,沒有登錄,校驗登錄信息
      			String token=request.getParameter("token");
      			if(StringUtils.isEmpty(token))//token不存在及用戶沒有登錄,非法訪問
      			{				
      				return ControllerHelper
      						.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST
      								, OAuthError.CodeResponse.ACCESS_DENIED
      								, ErrorConstants.ERROR_CLIENT_LOGIN);
       			}
      			else {//校驗token 服務器端對應的token是否存在,及獲取用戶信息等
      //				checktoken()
      			}
      			//生成受權碼
      			String authcode=null;
      			String responseType=oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);
      			if(responseType.equals(ResponseType.CODE.toString()))
      			{
      				OAuthIssuerImpl oAuthIssuerImpl=new OAuthIssuerImpl(new MD5Generator());
      				authcode=oAuthIssuerImpl.authorizationCode();
      				//保存受權碼
      				oauthClientService.saveCode(clientId, authcode);				
      			}
      			//Oauth 響應
      			OAuthASResponse.OAuthAuthorizationResponseBuilder builder=
      					OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
      			//設置受權碼
      			builder.setCode(authcode);
      			String redirectURI=oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
      			
      			oAuthResponse=builder.location(redirectURI).buildQueryMessage();
      			 //根據OAuthResponse返回ResponseEntity響應
                  HttpHeaders headers = new HttpHeaders();
                  headers.setLocation(new URI(oAuthResponse.getLocationUri()));
                  return new ResponseEntity(headers, HttpStatus.valueOf(oAuthResponse.getResponseStatus()));
      			
      			
      		} catch (Exception e) {
      			logger.error(e.getCause().getMessage(),e);
      		}
      		return null;
      	}
      

        


  2. 獲取訪問令牌
  1. 將請求轉換成oltu的token 獲取請求OAuthTokenRequest
  2. 從OauthTokenRequest讀取客戶端信息
  3. 校驗客戶端信息
  4. 生成訪問令牌token
  5. 存儲訪問令牌
  6. 構建oauth2響應oAuthResponse
  7. 返回到客戶端
public Object getToken(HttpServletRequest request) throws OAuthSystemException {
		try {
			OAuthTokenRequest oAuthTokenRequest= new OAuthTokenRequest(request);
			String clientId=oAuthTokenRequest.getClientId();
			String clientKey= oAuthTokenRequest.getClientSecret();
			
			if(!oauthClientService.checkClient(clientId,clientKey))
			{
				return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, OAuthError.TokenResponse.INVALID_CLIENT, ErrorConstants.ERROR_CLIENT_MSG);
			}
			OAuthResponse oAuthResponse;
			
			String authcode= oAuthTokenRequest.getCode();
			String grantType= oAuthTokenRequest.getGrantType();
			if(GrantType.AUTHORIZATION_CODE.toString().equals(grantType) && authcode.equals(oauthClientService.getCode(clientId)))
			{
				//生成token				
	            OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
	            final String accessToken = oauthIssuerImpl.accessToken();
	            oauthClientService.saveAccessToken(accessToken, "");


	            //生成OAuth響應
	            oAuthResponse = OAuthASResponse
	                    .tokenResponse(HttpServletResponse.SC_OK)
	                    .setAccessToken(accessToken)	                   
	                    .setExpiresIn(String.valueOf( 3600L))
	                    .buildJSONMessage();

	            //根據OAuthResponse生成ResponseEntity
	            return new ResponseEntity(oAuthResponse.getBody(), HttpStatus.valueOf(oAuthResponse.getResponseStatus()));
				
			}
			else{
				return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, OAuthError.TokenResponse.INVALID_GRANT, ErrorConstants.ERROR_AUTH_CODE);
			}
			
			
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, ErrorConstants.ERROR_UNKNOW, e.getCause().getMessage());
		}		
	}

  

客戶端主要有一下兩個接口

/requestAuth: 重定向到拼接好的受權請求url

 

	@RequestMapping("/requestAuth")
	public ModelAndView requestAuth(@ModelAttribute("oauthParams") OauthParam oauthParams) {
		try {
			 OAuthClientRequest request = OAuthClientRequest
		                .authorizationLocation(oauthParams.getAuthzEndpoint())
		                .setClientId(oauthParams.getClientId())
		                .setRedirectURI(oauthParams.getRedirectUri())
		                .setResponseType(ResponseType.CODE.toString())
		                .setScope(oauthParams.getScope())
		                .setState(oauthParams.getState())
		                .buildQueryMessage();

		     return new ModelAndView(new RedirectView(request.getLocationUri()));
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return null;
		}
	}

  

/redirect:獲取受權碼後,處理受權碼的重定向地址。

 

  OAuthAuthzResponse oar = null;
  oar = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
  String code = oar.getCode();//獲取受權碼
  OAuthClientRequest request2 =OAuthClientRequest
	           		.tokenLocation(oauthParams.getTokenEndpoint())
	           		.setClientId(oauthParams.getClientId())
	           		.setClientSecret(oauthParams.getClientSecret())
	           		.setRedirectURI(oauthParams.getRedirectUri())
	           		.setCode(code)
	           		.setGrantType(GrantType.AUTHORIZATION_CODE)
	           		.buildBodyMessage();
	           
 OAuthClient client=new OAuthClient(new URLConnectionClient());
	           
 Class<? extends OAuthAccessTokenResponse> cl = OAuthJSONAccessTokenResponse.class;
	           //請求token
 OAuthAccessTokenResponse oauthResponse=client.accessToken(request2,cl);
 String token=oauthResponse.getAccessToken();//獲取token

 源碼地址:https://github.com/huanglin101/springboot_oltu_oauth2.git

相關文章
相關標籤/搜索