自定义spring security oauth2 /oauth/token以及token失效/过期的返回内容格式

前言

在整合Spring Security Oauth2的时候,获取token的接口/oauth/token的返回内容格式为固定的,如下图所示:

自定义spring security oauth2 /oauth/token以及token失效/过期的返回内容格式

而token过期或者无效的返回参数格式如下图所示:

自定义spring security oauth2 /oauth/token以及token失效/过期的返回内容格式

实际在我们的项目中有时候会要求自定义返回内容格式,下面分别介绍获取token和token失效/过期的自定义返回内容格式。


自定义获取token接口的参数格式

1、创建接收获取token接口返回参数的实体

@Data
public class OauthResult {

    private String code;

    private String mesg;
}
@JsonSerialize(using = ResponseSerializer.class)
@Data
public class OauthResponse extends OauthResult{

    private Object data;
}

2、创建获取token接口返回值的转换类

创建一个类来完成对获取token接口的返回参数进行转换成我们自定义的格式,这里使用到了@JsonSerialize注解,该注解主要用于数据转换,不知道的可以自行百度

import com.bw.dsm.entity.OauthResponse;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.springframework.security.oauth2.common.OAuth2AccessToken;

import java.io.IOException;


public class ResponseSerializer extends StdSerializer<OauthResponse> {

    public ResponseSerializer() {
        super(OauthResponse.class);
    }

    @Override
    public void serialize(OauthResponse value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        OAuth2AccessToken oAuth2AccessToken = (OAuth2AccessToken) value.getData();

        gen.writeStartObject();
        if (oAuth2AccessToken != null){
            gen.writeStringField("code", value.getCode());
            gen.writeStringField("mesg", value.getMesg());

            gen.writeObjectFieldStart("data");
            gen.writeStringField("accessToken", oAuth2AccessToken.getValue());
            gen.writeNumberField("expiresIn",oAuth2AccessToken.getExpiresIn());
            gen.writeEndObject();
        } else {
            gen.writeStringField("code", "1");
            gen.writeStringField("mesg", "获取token失败");
        }

        gen.writeEndObject();
    }
}

3、新建切面类,将ResponseEntity进行重新组织,改变返回值

自定义切点,对postAccessToken方法进行增强,该方法是/oauth/token接口的返回方法,在这个方法的基础上改变返回值即可。

import com.bw.dsm.entity.OauthResponse;
import com.bw.dsm.util.AES128Util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AuthTokenAspect {

    private Logger logger = LoggerFactory.getLogger(getClass());

    /// @Around是可以改变controller返回值的
    @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
        // 放行
        OauthResponse response = new OauthResponse();
        ObjectMapper mapper = new ObjectMapper();
        try {
            Object proceed = pjp.proceed();
            if (proceed != null) {
                ResponseEntity<OAuth2AccessToken> responseEntity = (ResponseEntity<OAuth2AccessToken>)proceed;
                OAuth2AccessToken body = responseEntity.getBody();
                if (responseEntity.getStatusCode().is2xxSuccessful()) {
                    response.setCode("0");
                    response.setMesg("");
                    response.setData(body);
                } else {
                    logger.error("error:{}", responseEntity.getStatusCode().toString());
                    response.setCode("1");
                    response.setMesg("获取token失败");
                }
            }
        } catch (Exception e){
            response.setCode("1");
            response.setMesg("获取token失败");
        }
        String result = mapper.writeValueAsString(response);
        return ResponseEntity
                .status(200)
                .body(AES128Util.JiaMi(result));
    }
}

我这里还另外对返回值进行了加密,如果不需要加密则直接返回response,即:

return ResponseEntity
        .status(200)
        .body(response);

这样,返回格式就成了我们自定义的格式了,下面可以看下未加密的自定义返回格式:

获取token接口调用成功:

自定义spring security oauth2 /oauth/token以及token失效/过期的返回内容格式

获取token接口调用失败:

自定义spring security oauth2 /oauth/token以及token失效/过期的返回内容格式 

 


自定义token过期/无效的返回参数格式

1、在配置资源服务器的配置类中添加拦截

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        // 自定义token失效/错误返回信息
        OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
        authenticationEntryPoint.setExceptionTranslator(new CustomExceptionTranslator());
        resources.authenticationEntryPoint(authenticationEntryPoint);
    }
}

其他配置省略。按照各自业务需求来,这里只介绍自定义token过期/无效的返回参数格式。

2、自定义接收token无效/过期的错误信息转换类

import com.bw.dsm.util.AES128Util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;

public class CustomExceptionTranslator extends DefaultWebResponseExceptionTranslator {

    @Override
    public ResponseEntity translate(Exception e) throws Exception {
        ResponseEntity translate = super.translate(e);
        ObjectMapper mapper = new ObjectMapper();
        OAuth2Exception body = (OAuth2Exception) translate.getBody();
        CustomOauthException customOauthException = new CustomOauthException(body.getMessage(), body.getOAuth2ErrorCode(), String.valueOf(body.getHttpErrorCode()));
//        ResponseEntity response = new ResponseEntity<>(customOauthException, translate.getHeaders(), translate.getStatusCode());
        return ResponseEntity
                .status(translate.getStatusCode())
                .header(String.valueOf(translate.getHeaders()))
                .body(AES128Util.JiaMi(mapper.writeValueAsString(customOauthException)));
    }
}

同样的这里我也将返回参数加密处理,如果不需要加密,如下所示:

public class CustomExceptionTranslator extends DefaultWebResponseExceptionTranslator {

    @Override
    public ResponseEntity translate(Exception e) throws Exception {
        ResponseEntity translate = super.translate(e);
        ObjectMapper mapper = new ObjectMapper();
        OAuth2Exception body = (OAuth2Exception) translate.getBody();
        CustomOauthException customOauthException = new CustomOauthException(body.getMessage(), body.getOAuth2ErrorCode(), String.valueOf(body.getHttpErrorCode()));
        ResponseEntity response = new ResponseEntity<>(customOauthException, translate.getHeaders(), translate.getStatusCode());
        return response;
    }
}

3、创建自定义token无效/过期返回参数格式类

@JsonSerialize(using = CustomOauthExceptionSerializer.class)
public class CustomOauthException extends OAuth2Exception {

    private String code;

    private String mesg;

    public CustomOauthException(String msg, String code, String mesg){
        super(msg);
        this.code = code;
        this.mesg = mesg;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMasg() {
        return mesg;
    }

    public void setMasg(String mesg) {
        this.mesg = mesg;
    }
}

4、token无效或过期返回值转换类

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;

public class CustomOauthExceptionSerializer extends StdSerializer {

    public CustomOauthExceptionSerializer() {
        super(CustomOauthException.class);

    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeObjectField("code","1");
        gen.writeObjectField("mesg","token无效或已过期");
        gen.writeEndObject();
    }
}

这样,返回格式就成了我们自定义的格式了,下面可以看下未加密的自定义返回格式:

token无效返回:

自定义spring security oauth2 /oauth/token以及token失效/过期的返回内容格式

 

相关文章

暂无评论

暂无评论...