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

OAuth2.0原理与简单实现演示

程序员文章站 2022-05-20 13:45:27
...

最近在学习Oauth,趁有时间把一些实践经验和理解记录下来,目前oauth最新的版本是2.0,相比1.0更简单更安全,在企业的业务系统中可用来实现SSO

 

1OAuth的简述

OAuthOpen Authorization,开放授权)是为用户资源的授权定义了一个安全、开放及简单的标准,第三方无需知道用户的账号及密码,就可获取到用户的授权信息,并且这是安全的。

 

2、名称定义

在详细讲解OAuth 2.0之前,需要了解几个专用名词。它们对读懂后面的讲解,至关重要。

1Third-party application:第三方应用程序,本文中又称"客户端"client)。

2Resource Owner:资源所有者,本文中又称"用户"user)。

3User Agent:用户代理,本文中就是指浏览器。

4Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。

5Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

 

知道了上面这些名词,就不难理解,OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,与"服务商提供商"进行互动。

 

3OAuth的原理


OAuth2.0原理与简单实现演示
            
    
    博客分类: 授权 OAuth授权SSO 
 

 

上图是Oauth2.0其中的授权码模式(authorization code),因为这个模式比较常用,我主要学习这个为主,图中我分为5个步骤讲解

 

【A】    用户请求访问客户端,或者将前者导向至认证服务器,带上参数:client_idredirect_url

【B】    用户登录认证服务器,并选择是否授权给客户端访问

【C】    用户选择同意授权,认证服务器把用户导向至redirect_url,并且附上授权码(authorization code

【D】   客户端向认证服务器请求access token,需要带上参数:client_idclient_secretredirect_uri,和上一步获取的authorization code;认证服务器检查参数正确则返回access tonken表示授权成功

【E】    客户端使用access token请求资源服务器获取用户资源。

 

3、OAuth2.0简单实现(java

       国外有几个开源的java版的oauth实现,可以帮助较快的搭建一个oauth服务器,例如以下几个(可点击打开对应官网)

·         Java

·         Apache Oltu

·         Spring Security for OAuth

·         Apis Authorization Server (v2-31)

·         Restlet Framework (draft 30)

·         Apache CXF

 

 

Apache Oltu

目前我只是尝试了Oltu,比较轻量级,也不需要依赖其他服务,比较简单,但是官方的文档实在简陋,也是花了些时间才大概搞明白怎么用,下面就放出代码给大家演示下

 

服务端

获取授权码服务端代码示例

@RequestMapping("/authorize")

public ModelAndView authorize(HttpServletRequest request)

           throws OAuthSystemException, OAuthProblemException, URISyntaxException {

       ModelAndView mav = new ModelAndView();

       // 构建OAuth请求

       OAuthAuthzRequest oAuthzRequest = new OAuthAuthzRequest(request);

       // 获取OAuth客户端Id

       String clientId = oAuthzRequest.getClientId();

       // 校验客户端Id是否正确

       if (!checkClientId(clientId)) {

           mav.addObject("msg", "无效的客户ID");

           mav.setViewName("forward:/ljdp/oauth/authorizefail");

           returnmav;

       }

      

       //检查用户是否登陆和同意授权,如何还没登陆则跳转至登陆页面,然后进行授权提示

       //待开发。。。

      

      

       //生成授权码

       String authCode = null;

       String responseType = oAuthzRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);

       //ResponseType仅支持CODETOKEN

       if(responseType.equals(ResponseType.CODE.toString())){

           OAuthIssuerImpl oAuthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());

           authCode = oAuthIssuerImpl.authorizationCode();

           System.out.println("授权码="+authCode);

       }

      

       //获取客户端重定向地址

       String redirectURI = oAuthzRequest.getParam(OAuth.OAUTH_REDIRECT_URI);

       mav.setViewName("redirect:"+redirectURI+"?code="+authCode);

       returnmav;

}

 

 

获取Access Token服务端代码示例

@RequestMapping("/accesstoken")

public ResponseEntity<String> accessToken(HttpServletRequest request) throws OAuthSystemException, OAuthProblemException{

       //构建OAuth请求

       OAuthTokenRequest tokenRequest = new OAuthTokenRequest(request);

       //获取OAuth客户端Id

       String clientId = tokenRequest.getClientId();

       //校验客户端Id是否正确

       if(!checkClientId(clientId)){

           OAuthResponse oAuthResponse = OAuthASResponse

                  .errorResponse(HttpServletResponse.SC_BAD_REQUEST)

                  .setError(OAuthError.TokenResponse.INVALID_CLIENT)

                  .setErrorDescription("无效的客户端Id")

                  .buildJSONMessage();

           System.out.println(oAuthResponse.getBody());

           return new ResponseEntity<String>(oAuthResponse.getBody(), HttpStatus.valueOf(oAuthResponse.getResponseStatus()));

       }

      

       //检查客户端安全KEY是否正确

       if(!checkClientSecret(tokenRequest.getClientSecret())){

           OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)

                     .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)

                     .setErrorDescription("客户端安全KEY认证不通过")

                      .buildJSONMessage();

           return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

       }

      

       //检查redirect_uri是否和认证的一致

       if(!checkRedirectUri(tokenRequest.getRedirectURI())){

           OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)

                  .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)

                  .setErrorDescription("客户端认证不通过")

                  .buildJSONMessage();

           return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

       }

      

       //验证类型,有AUTHORIZATION_CODE/PASSWORD/REFRESH_TOKEN/CLIENT_CREDENTIALS

        if(tokenRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.AUTHORIZATION_CODE.toString())){

           String authCode = tokenRequest.getParam(OAuth.OAUTH_CODE);

           if(!checkAuthCode(authCode)){

              OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)

                     .setError(OAuthError.TokenResponse.INVALID_GRANT)

                       .setErrorDescription("错误的授权码") 

                       .buildJSONMessage();

              return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

           }

           //生成访问令牌

           OAuthIssuerImpl authIssuerImpl = new OAuthIssuerImpl(new MD5Generator());

           String accessToken = authIssuerImpl.accessToken();

          

           //生成OAuth响应

           OAuthResponse response = OAuthASResponse

                  .tokenResponse(HttpServletResponse.SC_OK)

                  .setAccessToken(accessToken)

                  .setExpiresIn("1000")

                  .buildJSONMessage();

           System.out.println(response.getBody());

//         HttpHeaders headers = new HttpHeaders();

//         headers.setContentType(MediaType.APPLICATION_JSON);

           return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

       }

      

       OAuthResponse response = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)

              .setError(OAuthError.TokenResponse.UNSUPPORTED_GRANT_TYPE)

                .setErrorDescription("不支持此授权类型") 

                .buildJSONMessage();

       return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

}

 

Accesstoken获取授权用户资源服务器端代码示例

@RequestMapping("/resource")

@ResponseBody

public AuthUserInfo resource(HttpServletRequest request, HttpServletResponse response) {

// Make the OAuth Request out of this request and validate it

    // Specify where you expect OAuth access token (request header, body

    // or query string)

    OAuthAccessResourceRequest oauthRequest =

new OAuthAccessResourceRequest(request, ParameterStyle.QUERY);

 

    // Get the access token

    String accessToken = oauthRequest.getAccessToken();

   

    // ... validate access token

 

    //验证通过返回用户信息

    return new AuthUserInfo("test", "测试");

}

 

 

客户

获取accessToken代码示例

OAuthClientRequest request = OAuthClientRequest

       //获取accesstoken地址

       .tokenLocation("http://localhost:8080/ljdp/oauth/accesstoken")

       //授权方式

       .setGrantType(GrantType.AUTHORIZATION_CODE)

       //你的clientidsecret

       .setClientId("your-application-client-id")

       .setClientSecret("your-application-client-secret")

       //第一步重定向的uri

       .setRedirectURI("http://localhost:8080/ljdp/oauth/getcode")

       //第一步获取的认证码

       .setCode("****")

       .buildQueryMessage();

 

//create OAuth client that uses custom http client under the hood

OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

 

//Custom response classes are an easy way to deal with oauth providers that introduce modifications to

//OAuth 2.0 specification

OAuthJSONAccessTokenResponse oAuthResponse = oAuthClient.accessToken(request, OAuthJSONAccessTokenResponse.class);

 

String accessToken = oAuthResponse.getAccessToken();

Long expiresIn = oAuthResponse.getExpiresIn();

 

accesstoken获取用户资源代码示例

OAuthClientRequest bearerClientRequest = new OAuthBearerClientRequest(

       "http://localhost:8080/ljdp/oauth/resource")

       .setAccessToken("********")

       .buildQueryMessage();

 

OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

 

OAuthResourceResponse resourceResponse = oAuthClient.resource(

       bearerClientRequest, OAuth.HttpMethod.GET,

       OAuthResourceResponse.class);

 

System.out.println(resourceResponse.getBody());

System.out.println(resourceResponse.getResponseCode());

 

 

 

 

 

  • OAuth2.0原理与简单实现演示
            
    
    博客分类: 授权 OAuth授权SSO 
  • 大小: 21.6 KB
相关标签: OAuth 授权 SSO