zoukankan      html  css  js  c++  java
  • Oauth2.0客户端服务端示例

    https://blog.csdn.net/qq_28165595/article/details/80459185

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

    回顾大致授权流程


    图中步骤1,请求授权,例如我们要登录csdn,这里我们想用qq账号登录,这时候就需要腾讯开放平台进行授权,具体操作如下图

    这里简单模拟,在客户端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;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    服务端代码
    /**
    * @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;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    上面的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;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    上面的代码对应上图的步骤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);
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    上段代码对应上图中的步骤6,验证accessToken,返回用户请求资源,这里简单用username来模拟用户请求的资源。
    服务端控制台输出如下


    相关依赖jar包
    客户端依赖jar包

    <dependency>
    <groupId>org.apache.oltu.oauth2</groupId>
    <artifactId>org.apache.oltu.oauth2.client</artifactId>
    <version>0.31</version>
    </dependency>
    1
    2
    3
    4
    5
    服务端依赖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>
    ---------------------
    作者:爱琴孩
    来源:CSDN
    原文:https://blog.csdn.net/qq_28165595/article/details/80459185
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    freopen
    字符
    map映射
    P3512 [POI2010]PIL-Pilots-洛谷luogu
    快读
    单调队列&单调栈
    简写
    邻接表&链式前向星
    mysql参数详解
    网络管理指南
  • 原文地址:https://www.cnblogs.com/guyuehuanhuan/p/9960870.html
Copyright © 2011-2022 走看看