Spring,Cloud,OAuth2中/oauth/token的返回内容格式
admin
2023-05-02 05:20:11
目录

    背景

    在前后端分离的项目中,一般后端返回给前端的格式是一个固定的json格式。在这个前提下,Spring Cloud OAuth2 生成access token的请求/oauth/token的返回内容就需要自定义。

    访问/oauth/token示例如下:


    原始返回值的格式如下:


    我们希望使用我们自己固定的json格式,如下:

    实现原理

    原理就是通过切面编程实现对/oauth/token端点请求的结果进行拦截封装处理,由于/oauth/token是Spring Cloud OAuth2的内部端点,因此需要对相关的Spring源码进行分析。最终定位到

    org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken()

    方法上。

    代码实现

    相关类

    CodeEnum.java

    package com.wongoing.common.model;
    
    /**
     * @description: 代码枚举
     * @author: zheng
     * @date: Created in 2021/1/26 11:18
     * @version: 0.0.1
     * @modified By:
     */
    public enum CodeEnum {
        SUCCESS(0),
        ERROR(1);
    
        private Integer code;
    
        CodeEnum(Integer code) {
            this.code = code;
        }
    
        public Integer getCode() {
            return this.code;
        }
    }
    

    Result.java

    package com.wongoing.common.model;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.io.Serializable;
    
    /**
     * @description: Rest API 接口方法返回类型定义
     * @author: zheng
     * @date: Created in 2021/1/26 13:25
     * @version: 0.0.1
     * @modified By:
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Result implements Serializable {
        private T data;
        private Integer code;
        private String msg;
    
        public static  Result of(T data, Integer code, String msg) {
            return new Result<>(data, code, msg);
        }
    
        public static  Result succeed(String msg) {
            return of(null, CodeEnum.SUCCESS.getCode(), msg);
        }
    
        public static  Result succeed(T model, String msg) {
            return of(model, CodeEnum.SUCCESS.getCode(), msg);
        }
    
        public static  Result succeed(T model) {
            return of(model, CodeEnum.SUCCESS.getCode(), "");
        }
    
        public static  Result failed(String msg) {
            return of(null, CodeEnum.ERROR.getCode(), msg);
        }
    
        public static  Result failed(T model, String msg) {
            return of(model, CodeEnum.ERROR.getCode(), msg);
        }
    }
    

    关键切面拦截器

    在uaa项目中定义OauthTokenAspect.java

    package com.wongoing.oauth2.filter;
    
    import com.wongoing.common.constant.SecurityConstants;
    import com.wongoing.common.context.TenantContextHolder;
    import com.wongoing.common.model.Result;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.authentication.InsufficientAuthenticationException;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.oauth2.common.OAuth2AccessToken;
    import org.springframework.security.oauth2.common.util.OAuth2Utils;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.stereotype.Component;
    
    import java.security.Principal;
    import java.util.Map;
    
    /**
     * @description: oauth-token拦截器
     * 1. 赋值租户
     * 2. 统一返回token格式
     *
     * @author: zheng
     * @date: Created in 2021/7/12 16:25
     * @version: 0.0.1
     * @modified By:
     */
    @Slf4j
    @Component
    @Aspect
    public class OauthTokenAspect {
    
        @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
        public Object handleControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
            try {
                Object[] args = joinPoint.getArgs();
                Principal principal = (Principal) args[0];
                if (!(principal instanceof Authentication)) {
                    throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");
                }
                String clientId = this.getClientId(principal);
                Map parameters = (Map) args[1];
                String grantType = parameters.get(OAuth2Utils.GRANT_TYPE);
    
                //保存租户id
                TenantContextHolder.setTenant(clientId);
                Object proceed = joinPoint.proceed();
                if (SecurityConstants.AUTHORIZATION_CODE.equals(grantType)) {
                    /**
                     * 如果使用 @EnableOAuth2Sso 注解不能修改返回格式,否则授权码模式可以统一改
                     * 因为本项目的 sso-demo/ss-sso 里面使用了 @EnableOAuth2Sso 注解,所以这里就不修改授权码模式的token返回值了
                     */
                    return proceed;
                } else {
                    ResponseEntity responseEntity = (ResponseEntity) proceed;
                    OAuth2AccessToken body = responseEntity.getBody();
                    return ResponseEntity
                            .status(HttpStatus.OK)
                            .body(Result.succeed(body));
                }
            } finally {
                TenantContextHolder.clear();
            }
        }
    
        private String getClientId(Principal principal) {
            Authentication client = (Authentication) principal;
            if (!client.isAuthenticated()) {
                throw new InsufficientAuthenticationException("The client is not authenticated.");
            }
            String clientId = client.getName();
            if (client instanceof OAuth2Authentication) {
                clientId = ((OAuth2Authentication) client).getOAuth2Request().getClientId();
            }
            return clientId;
        }
    }
    

    其中的常量值:

    public abstract class OAuth2Utils {
    	public static final String GRANT_TYPE = "grant_type";
    }
    

    public interface SecurityConstants {
    	/**
         * 授权码模式
         */
        String AUTHORIZATION_CODE = "authorization_code";
    }
    

    到此这篇关于Spring Cloud OAuth2中/oauth/token的返回内容格式的文章就介绍到这了,更多相关Spring Cloud OAuth2返回内容格式内容请搜索趣讯吧以前的文章或继续浏览下面的相关文章希望大家以后多多支持趣讯吧!

    相关内容

    热门资讯

    demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
    北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
    苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
    世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
    长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
    猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
    阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
    应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
    脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
    demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
    北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
    苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
    长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
    脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
    应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
    阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
    猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
    demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...