欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Oauth2.0客户端服务端示例

程序员文章站 2022-06-13 15:46:04
...

前言

前面的理解OAuth2.0认证与客户端授权码模式详解,我们大致了解了Oauth2.0授权模式四种的授权码模式,清楚了授权码模式的大致流程。这里简单的模拟一下基于授权码模式的客户端和服务端代码实现(这里服务端包含的验证服务端和资源服务端,都是在同一个应用中)。

回顾大致授权流程

Oauth2.0客户端服务端示例

  • 图中步骤1,请求授权,例如我们要登录csdn,这里我们想用qq账号登录,这时候就需要腾讯开放平台进行授权,具体操作如下图
    Oauth2.0客户端服务端示例
    这里简单模拟,在客户端web项目中构造一个oauth的客户端请求对象(OAuthClientRequest),在此对象中携带客户端信息(clientId、accessTokenUrl、response_type、redirectUrl),将此信息放入http请求中,重定向到服务端。
  • 上图步骤2,在服务端web项目中接受第一步传过来的request,从中获取客户端信息,可以自行验证信息的可靠性。同时构造一个oauth的code授权许可对象(OAuthAuthorizationResponseBuilder),并在其中设置授权码code,将此对象传回客户端。
  • 上图步骤3,在在客户端web项目中接受第二步的请求request,从中获得code。同时构造一个oauth的客户端请求对象(OAuthClientRequest),此次在此对象中不仅要携带客户端信息(clientId、accessTokenUrl、clientSecret、GrantType、redirectUrl),还要携带接受到的code。再构造一个客户端请求工具对象(oAuthClient),这个工具封装了httpclient,用此对象将这些信息以post的方式请求到服务端,目的是为了让服务端返回资源访问令牌。
  • 上图步骤4,在服务端web项目中接受第三步传过来的request,从中获取客户端信息和code,并自行验证。再按照自己项目的要求生成访问令牌(accesstoken),同时构造一个oauth响应对象(OAuthASResponse),携带生成的访问指令(accesstoken),返回给第三步中客户端的oAuthClient。oAuthClient接受响应之后获取accesstoken。
  • 上图步骤5,此时客户端web项目中已经有了从服务端返回过来的accesstoken,那么在客户端构造一个服务端资源请求对象(OAuthBearerClientRequest),在此对象中设置服务端资源请求URI,并携带上accesstoken。再构造一个客户端请求工具对象(oAuthClient),用此对象去服务端靠accesstoken换取资源。
  • 上图步骤6,在服务端web项目中接受第五步传过来的request,从中获取accesstoken并自行验证。之后就可以将客户端请求的资源返回给客户端了。

客户端代码

/**
* @ClassName: ClientController 
* @Description: Oauth客户端 
* @author qinhaihai 
* @date 2018年5月24日
*
 */
@Controller
@RequestMapping("/clientController")
public class ClientController{
    String clientId = null;
    String clientSecret = null;
    String accessTokenUrl = null;
    String userInfoUrl = null;
    String redirectUrl = null;
    String response_type = null;
    String code= null;

    //提交申请code的请求,对应上图中的步骤一
    @RequestMapping("/requestServerCode")
    public String requestServerCode(HttpServletRequest request, HttpServletResponse response) 
            throws OAuthProblemException{
        clientId = "clientId";
        accessTokenUrl = "responseCode";
        redirectUrl = "http://localhost:8081/oauthclient01/clientController/callbackCode";
        response_type = "code";
        String requestUrl = null;
        try {
            //构建oauth的请求。设置授权服务地址(accessTokenUrl)、clientId、response_type、redirectUrl
            OAuthClientRequest accessTokenRequest = OAuthClientRequest
            .authorizationLocation(accessTokenUrl)
            .setResponseType(response_type)
            .setClientId(clientId)
            .setRedirectURI(redirectUrl)
            .buildQueryMessage();
            requestUrl = accessTokenRequest.getLocationUri();
            System.out.println("获取授权码方法中的requestUrl的值----"+requestUrl);
        } catch (OAuthSystemException e) {
            e.printStackTrace();
        }
        return "redirect:http://localhost:8082/oauthserver/"+requestUrl ;
    }

    //接受客户端返回的code,提交申请access token的请求,对应上图中的步骤三
    @RequestMapping("/callbackCode")
    public Object toLogin(HttpServletRequest request) throws OAuthProblemException{
        clientId = "clientId";
        clientSecret = "clientSecret";
        accessTokenUrl="http://localhost:8082/oauthserver/responseAccessToken";
        userInfoUrl = "userInfoUrl";
        redirectUrl = "http://localhost:8081/oauthclient01/clientController/accessToken";
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
        try {
            OAuthClientRequest accessTokenRequest = OAuthClientRequest
                .tokenLocation(accessTokenUrl)
                    .setGrantType(GrantType.AUTHORIZATION_CODE)
                    .setClientId(clientId)
                    .setClientSecret(clientSecret)
                    .setCode(httpRequest.getParameter("code"))
                    .setRedirectURI(redirectUrl)
                    .buildQueryMessage();
            //去服务端请求access token,并返回响应
            OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);
            //获取服务端返回过来的access token 
            String accessToken = oAuthResponse.getAccessToken();
            //查看access token是否过期
            //Long expiresIn = oAuthResponse.getExpiresIn();
            return "redirect:http://localhost:8081/oauthclient01/clientController/accessToken?accessToken="+accessToken;
        } catch (OAuthSystemException e) {
            e.printStackTrace();
        }
        return null;
    }

    //接受服务端传回来的access token,由此token去请求服务端的资源(用户信息等),对应上图中的步骤五
    @RequestMapping("/accessToken")
    public ModelAndView accessToken(String accessToken) {
        userInfoUrl = "http://localhost:8082/oauthserver/userInfo";
        OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
        try {
            OAuthClientRequest userInfoRequest = new OAuthBearerClientRequest(userInfoUrl)
            .setAccessToken(accessToken).buildQueryMessage();
            OAuthResourceResponse resourceResponse = oAuthClient.resource(userInfoRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);
            String username = resourceResponse.getBody();
            ModelAndView modelAndView = new ModelAndView("usernamePage");
            modelAndView.addObject("username", username);
            return modelAndView;
        } catch (OAuthSystemException e) {
            e.printStackTrace();
        } catch (OAuthProblemException e) {
            e.printStackTrace();
        }
        return null;
    }
}

服务端代码

/**
* @ClassName: AuthorizeController 
* @Description: 服务端授权Controller 
* @author aiqinhai 
* @date 2018年5月24日 下午10:00:01 
*/
@Controller
public class AuthorizeController{
    //向客户端返回授权许可码 code,对应上图中的步骤二
    @RequestMapping("/responseCode")
    public Object responseCode(Model model,HttpServletRequest request){
      try {
      //构建OAuth 授权请求  
      OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request); 
      System.out.println("授权服务器获取的clientID----"+oauthRequest.getClientId());
      System.out.println("返回类型----"+oauthRequest.getResponseType());
      System.out.println("重定向地址---"+oauthRequest.getRedirectURI());
      if(oauthRequest.getClientId()!=null&&oauthRequest.getClientId()!=""){
        //设置授权码  
        String authorizationCode = "authorizationCode";
        //进行OAuth响应构建
        OAuthASResponse.OAuthAuthorizationResponseBuilder builder =
        OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
        //设置授权码
        builder.setCode(authorizationCode);
        //得到到客户端重定向地址
        String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
        //构建响应
        final OAuthResponse response = builder.location(redirectURI).
                buildQueryMessage();
        String responceUri =response.getLocationUri();
        System.out.println("redirectURI是----"+redirectURI);
        System.out.println("responceUri是----"+responceUri);
        //根据OAuthResponse返回ResponseEntity响应
        HttpHeaders headers = new HttpHeaders();
        try {
            headers.setLocation(new URI(responceUri));
          } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        return "redirect:"+responceUri;
        }
    } catch (OAuthSystemException e) {
        e.printStackTrace();
    } catch (OAuthProblemException e) {
        e.printStackTrace();
    }
    return null;
    }
}

上面的responseCode,对应了上图的步骤二,返回authorizationCode授权码到客户端。

/**
 * 
* @ClassName: AccessTokenController 
* @Description: 根据授权码生成accessToken
* @author aiqinlhai 
* @date 2018年5月24日
 */
@Controller
public class AccessTokenController {

    //获取客户端的code码,向客户端返回access token
    @RequestMapping(value="/responseAccessToken",method = RequestMethod.POST)  
    public HttpEntity token(HttpServletRequest request){
        OAuthIssuer oauthIssuerImpl=null;
        OAuthResponse response=null;
        //构建OAuth请求  
          try {
            OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request);
            String authCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
            System.out.println("客户端传过来的授权码是----"+authCode);
            String clientSecret = oauthRequest.getClientSecret();
            if(clientSecret!=null||clientSecret!=""){
                //生成Access Token
                oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
                final String accessToken = oauthIssuerImpl.accessToken();
                System.out.println(accessToken);
                //生成OAuth响应
                response = OAuthASResponse
                .tokenResponse(HttpServletResponse.SC_OK)
                .setAccessToken(accessToken)
                .buildJSONMessage();
            }
          //根据OAuthResponse生成ResponseEntity
            return new ResponseEntity<String>(response.getBody(), 
                    HttpStatus.valueOf(response.getResponseStatus()));
        } catch (OAuthSystemException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (OAuthProblemException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

上面的代码对应上图的步骤4,验证客户端的授权码,并返回accessToken。

/**
 * 
* @ClassName: UserInfoController 
* @Description: 根据客户端的accessToken来返回用户信息到客户端
* @author aiqinhai 
* @date 2018年5月24
 */
@Controller
public class UserInfoController {
    @RequestMapping("/userInfo") 
    public HttpEntity<String> userInfo(HttpServletRequest request) 
            throws OAuthSystemException{   
        try {
            //获取客户端传来的OAuth资源请求
            OAuthAccessResourceRequest oauthRequest = new 
                    OAuthAccessResourceRequest(request, ParameterStyle.QUERY);
            //获取Access Token  
              String accessToken = oauthRequest.getAccessToken();  
              System.out.println("从客户端获取的accessToken----"+accessToken);
              //验证Access Token  
              if (accessToken==null||accessToken=="") {  
              // 如果不存在/过期了,返回未验证错误,需重新验证  
              OAuthResponse oauthResponse = OAuthRSResponse  
              .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)  
              .setError(OAuthError.ResourceResponse.INVALID_TOKEN)  
              .buildHeaderMessage();  
              HttpHeaders headers = new HttpHeaders();  
              headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,   
              oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));  
              return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);  
              }
              //这里没有从数据库查询了,简单指定为"aiqinhai"  
              String username="aiqinhai";
              return new ResponseEntity<String>(username, HttpStatus.OK);  
        } catch (OAuthProblemException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          //检查是否设置了错误码  
          String errorCode = e.getError();  
          if (OAuthUtils.isEmpty(errorCode)) {  
            OAuthResponse oauthResponse = OAuthRSResponse  
           .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)  
           .buildHeaderMessage();  
            HttpHeaders headers = new HttpHeaders();  
            headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,   
            oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));  
            return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);  
          }  
          OAuthResponse oauthResponse = OAuthRSResponse  
           .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)  
           .setError(e.getError())  
           .setErrorDescription(e.getDescription())  
           .setErrorUri(e.getUri())  
           .buildHeaderMessage();  
          HttpHeaders headers = new HttpHeaders();  
          headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,   
            oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));  
          return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);  
        }  
    }
}

上段代码对应上图中的步骤6,验证accessToken,返回用户请求资源,这里简单用username来模拟用户请求的资源。
服务端控制台输出如下
Oauth2.0客户端服务端示例

相关依赖jar包

客户端依赖jar包

<dependency>  
<groupId>org.apache.oltu.oauth2</groupId>  
<artifactId>org.apache.oltu.oauth2.client</artifactId>  
<version>0.31</version>  
</dependency>

服务端依赖jar包

 <dependency>  
      <groupId>org.apache.oltu.oauth2</groupId>  
      <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>  
      <version>0.31</version>  
  </dependency>  
  <dependency>  
      <groupId>org.apache.oltu.oauth2</groupId>  
      <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>  
      <version>0.31</version>  
 </dependency> 
相关标签: java Oauth2.0