oauth简单使用

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介:

v一、oauth原理参考

  理解OAuth 2.0

v二、本例中采用授权码模式

  

  大致流程

  (A)用户访问客户端,后者将前者导向认证服务器。
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。
(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

  参数含义

  response_type:表示授权类型,必选项,此处的值固定为"code"
client_id:表示客户端的ID,必选项
redirect_uri:表示重定向URI,可选项
scope:表示申请的权限范围,可选项,本例中无
state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值,本例中无

v三、项目中依赖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>
复制代码

v四、获取授权码

复制代码
/**
 * 获取授权码-服务端
 *
 * @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));
    }
}
复制代码

v五、根据授权码获取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));
    }

}
复制代码

v 六、简单测试

复制代码
@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));
}
复制代码

v七、项目地址

  oauth认证demo下载










本文转自 小眼儿 博客园博客,原文链接:http://www.cnblogs.com/hujunzheng/p/7126766.html,如需转载请自行联系原作者
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
6月前
|
JSON JavaScript 前端开发
❤Nodejs 第九章(token身份认证和express-jwt的安装认识)
【4月更文挑战第9天】Node.js第九章介绍了Token身份认证,特别是JWT(JSON Web Token)作为跨域认证的解决方案。JWT由Header、Payload和Signature三部分组成,用于在客户端和服务器间安全传输用户信息。前端收到JWT后存储在localStorage或sessionStorage中,并在请求头中发送。Express-JWT是一个中间件,用于解析JWT。基本用法包括设置secret和algorithms。注意安全问题,避免混合使用不同算法以防止降级攻击。
111 0
|
6月前
|
JSON 安全 API
在Python Web开发过程中:请简要介绍OAuth和JWT两种认证方式,并说明何时使用它们。
OAuth是开放授权协议,用于第三方应用安全访问用户资源;JWT是JSON格式的安全令牌,用于传递身份和权限。OAuth适合第三方登录和API访问,JWT适用于单点登录和分布式系统中的身份验证。选择取决于应用场景,两者都需确保安全实施,如加密和签名验证。
50 4
|
6月前
|
JSON 安全 API
【专栏】四种REST API身份验证方法:基本认证、OAuth、JSON Web Token(JWT)和API密钥
【4月更文挑战第28天】本文探讨了四种REST API身份验证方法:基本认证、OAuth、JSON Web Token(JWT)和API密钥。基本认证简单但不安全;OAuth适用于授权第三方应用;JWT提供安全的身份验证信息传递;API密钥适合内部使用。选择方法时需平衡安全性、用户体验和开发复杂性。
798 0
|
中间件
eggjs 怎么使用 egg-jwt 实现登录验证中间件?
eggjs 怎么使用 egg-jwt 实现登录验证中间件?
466 9
eggjs 怎么使用 egg-jwt 实现登录验证中间件?
|
数据安全/隐私保护
eggjs 怎么使用 egg-jwt 进行用户鉴权实现登录功能?
eggjs 怎么使用 egg-jwt 进行用户鉴权实现登录功能?
451 0
eggjs 怎么使用 egg-jwt 进行用户鉴权实现登录功能?
eggjs 怎么使用 egg-jwt 实现 token 解析?
eggjs 怎么使用 egg-jwt 实现 token 解析?
244 0
eggjs 怎么使用 egg-jwt 实现 token 解析?
|
存储 安全 Java
OAuth2在项目中使用完成的功能说明|学习笔记
快速学习OAuth2在项目中使用完成的功能说明
OAuth2在项目中使用完成的功能说明|学习笔记
|
安全 前端开发 JavaScript
OAuth2.0实战(二)四种认证方式的基本使用
OAuth2.0实战(二)四种认证方式的基本使用
487 0
OAuth2.0实战(二)四种认证方式的基本使用
|
API 开发者 Python
第 88 天:OAuth2.0 客户端实战
第 88 天:OAuth2.0 客户端实战
387 0
第 88 天:OAuth2.0 客户端实战
|
前端开发
Koa 鉴权实战 - OAuth
Koa 鉴权实战 - OAuth