1. 程式人生 > 程式設計 >Spring Cloud OAuth2中/oauth/token的返回內容格式

Spring Cloud OAuth2中/oauth/token的返回內容格式

目錄
  • 背景
  • 實現原理
  • 程式碼實現
    • 相關類
    • 關鍵切面攔截器

背景

在前後端分離的專案中,一般後端返回給前端的格式是一個固定的on格式。在這個前提下,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.

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<T> implements Serializable {
    private T data;
    private Integer code;
    private String msg;

    public static <T> Result<T> of(T data,Integer code,String msg) {
        return new Result<>(data,code,msg);
    }

    public static <T> Result<T> succeed(String msg) {
        return of(null,CodeEnum.SUCCESS.getCode(),msg);
    }

    public static <T> Result<T> succeed(T model,String msg) {
        return of(model,msg);
    }

    public static <T> Result<T> succeed(T model) {
        return of(model,"");
    }

    public static <T> Result<T> failed(String msg) {
        return of(null,CodeEnum.ERROR.getCode(),msg);
    }

    public static <T> Result<T> failed(T model,msg);
    }
}

關鍵切面攔截器

在uaa專案中定義OauthTokenAspect.java

package com.wongoing.oauth2.filter;

import com.wongoing.common.constant.SecurityC程式設計客棧onstants;
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.shttp://www.cppcns.comecurity.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<String,String> parameters = (Map<String,String>) 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<OAuth2AccessToken> responseEntity = (ResponseEntity<OAuth2AccessToken>) 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 OAuth2AuthenticatPiGnUion) {
            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返回內容格式內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!