付出就要得到回报,这种想法是错的。

前言

在使用Spring Security Oauth2登录和鉴权失败时,默认返回的异常信息如下

  1. {
  2. "error": "unauthorized",
  3. "error_description": "Full authentication is required to access this resource"
  4. }

。它与我们自定义返回信息不一致,并且描述信息较少。那么如何自定义Spring Security Oauth2异常信息呢,下面我们简单实现以下。格式如下:


  1. {
  2. "error": "400",
  3. "message": "坏的凭证",
  4. "path": "/oauth/token",
  5. "timestamp": "1527432468717"
  6. }

自定义登录失败异常信息

新增CustomOauthException

  • 添加自定义异常类,指定json序列化方式
  1. @JsonSerialize(using = CustomOauthExceptionSerializer.class)
  2. public class CustomOauthException extends OAuth2Exception {
  3. public CustomOauthException(String msg) {
  4. super(msg);
  5. }
  6. }

新增CustomOauthExceptionSerializer

  • 添加CustomOauthException的序列化实现
  1. public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> {
  2. public CustomOauthExceptionSerializer() {
  3. super(CustomOauthException.class);
  4. }
  5. @Override
  6. public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {
  7. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  8. gen.writeStartObject();
  9. gen.writeStringField("error", String.valueOf(value.getHttpErrorCode()));
  10. gen.writeStringField("message", value.getMessage());
  11. // gen.writeStringField("message", "用户名或密码错误");
  12. gen.writeStringField("path", request.getServletPath());
  13. gen.writeStringField("timestamp", String.valueOf(new Date().getTime()));
  14. if (value.getAdditionalInformation()!=null) {
  15. for (Map.Entry<String, String> entry : value.getAdditionalInformation().entrySet()) {
  16. String key = entry.getKey();
  17. String add = entry.getValue();
  18. gen.writeStringField(key, add);
  19. }
  20. }
  21. gen.writeEndObject();
  22. }
  23. }

添加CustomWebResponseExceptionTranslator

  • 添加CustomWebResponseExceptionTranslator,登录发生异常时指定exceptionTranslator
  1. public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> {
  2. public CustomOauthExceptionSerializer() {
  3. super(CustomOauthException.class);
  4. }
  5. @Override
  6. public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {
  7. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  8. gen.writeStartObject();
  9. gen.writeStringField("error", String.valueOf(value.getHttpErrorCode()));
  10. gen.writeStringField("message", value.getMessage());
  11. // gen.writeStringField("message", "用户名或密码错误");
  12. gen.writeStringField("path", request.getServletPath());
  13. gen.writeStringField("timestamp", String.valueOf(new Date().getTime()));
  14. if (value.getAdditionalInformation()!=null) {
  15. for (Map.Entry<String, String> entry : value.getAdditionalInformation().entrySet()) {
  16. String key = entry.getKey();
  17. String add = entry.getValue();
  18. gen.writeStringField(key, add);
  19. }
  20. }
  21. gen.writeEndObject();
  22. }
  23. }

修改MerryyouAuthorizationServerConfig

  • 指定自定义customWebResponseExceptionTranslator
  1. @Override
  2. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  3. endpoints.tokenStore(tokenStore)
  4. .authenticationManager(authenticationManager)
  5. .userDetailsService(userDetailsService);
  6. //扩展token返回结果
  7. if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
  8. TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
  9. List<TokenEnhancer> enhancerList = new ArrayList();
  10. enhancerList.add(jwtTokenEnhancer);
  11. enhancerList.add(jwtAccessTokenConverter);
  12. tokenEnhancerChain.setTokenEnhancers(enhancerList);
  13. //jwt
  14. endpoints.tokenEnhancer(tokenEnhancerChain)
  15. .accessTokenConverter(jwtAccessTokenConverter);
  16. }
  17. endpoints.exceptionTranslator(customWebResponseExceptionTranslator);
  18. }

自定义Token异常信息

添加AuthExceptionEntryPoint

  • 自定义AuthExceptionEntryPoint用于tokan校验失败返回信息
  1. public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
  2. @Override
  3. public void commence(HttpServletRequest request, HttpServletResponse response,
  4. AuthenticationException authException)
  5. throws ServletException {
  6. Map map = new HashMap();
  7. map.put("error", "401");
  8. map.put("message", authException.getMessage());
  9. map.put("path", request.getServletPath());
  10. map.put("timestamp", String.valueOf(new Date().getTime()));
  11. response.setContentType("application/json");
  12. response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  13. try {
  14. ObjectMapper mapper = new ObjectMapper();
  15. mapper.writeValue(response.getOutputStream(), map);
  16. } catch (Exception e) {
  17. throw new ServletException();
  18. }
  19. }
  20. }

添加CustomAccessDeniedHandler

  • 授权失败(forbidden)时返回信息
  1. @Slf4j
  2. @Component("customAccessDeniedHandler")
  3. public class CustomAccessDeniedHandler implements AccessDeniedHandler {
  4. @Autowired
  5. private ObjectMapper objectMapper;
  6. @Override
  7. public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
  8. response.setContentType("application/json;charset=UTF-8");
  9. Map map = new HashMap();
  10. map.put("error", "400");
  11. map.put("message", accessDeniedException.getMessage());
  12. map.put("path", request.getServletPath());
  13. map.put("timestamp", String.valueOf(new Date().getTime()));
  14. response.setContentType("application/json");
  15. response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  16. response.getWriter().write(objectMapper.writeValueAsString(map));
  17. }
  18. }

修改MerryyouResourceServerConfig

  1. @Override
  2. public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  3. resources.authenticationEntryPoint(new AuthExceptionEntryPoint())
  4. .accessDeniedHandler(CustomAccessDeniedHandler);
  5. }

效果如下

登录异常

token异常

禁止访问

token失效

代码下载

推荐文章

  1. Java创建区块链系列
  2. Spring Security源码分析系列
  3. Spring Data Jpa 系列
  4. 【译】数据结构中关于树的一切(java版)
  5. SpringBoot+Docker+Git+Jenkins实现简易的持续集成和持续部署

Spring Security Oauth2 自定义 OAuth2 Exception的更多相关文章

  1. 朱晔和你聊Spring系列S1E10:强大且复杂的Spring Security(含OAuth2三角色+三模式完整例子)

    Spring Security功能多,组件抽象程度高,配置方式多样,导致了Spring Security强大且复杂的特性.Spring Security的学习成本几乎是Spring家族中最高的,Spr ...

  2. spring security使用自定义登录界面后,不能返回到之前的请求界面的问题

    昨天因为集成spring security oauth2,所以对之前spring security的配置进行了一些修改,然后就导致登录后不能正确跳转回被拦截的页面,而是返回到localhost根目录. ...

  3. spring security采用自定义登录页和退出功能

    更新... 首先采用的是XML配置方式,请先查看  初识Spring security-添加security 在之前的示例中进行代码修改 项目结构如下: 一.修改spring-security.xml ...

  4. spring security 3 自定义认证,授权示例

    1,建一个web project,并导入所有需要的lib. 2,配置web.xml,使用Spring的机制装载: <?xml version="1.0" encoding=& ...

  5. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_06-SpringSecurityOauth2研究-Oauth2授权码模式-申请令牌

    3.3 Oauth2授权码模式 3.3.1 Oauth2授权模式 Oauth2有以下授权模式: 授权码模式(Authorization Code) 隐式授权模式(Implicit) 密码模式(Reso ...

  6. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_07-SpringSecurityOauth2研究-Oauth2授权码模式-资源服务授权测试

    下面要完成  5.6两个步骤 3.3.4 资源服务授权 3.3.4.1 资源服务授权流程 资源服务拥有要访问的受保护资源,客户端携带令牌访问资源服务,如果令牌合法则可成功访问资源服务中的资 源,如下图 ...

  7. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_09-SpringSecurityOauth2研究-Oauth2密码模式授权

    密码模式(Resource Owner Password Credentials)与授权码模式的区别是申请令牌不再使用授权码,而是直接 通过用户名和密码即可申请令牌. 测试如下: Post请求:htt ...

  8. spring security 之自定义表单登录源码跟踪

    ​ 上一节我们跟踪了security的默认登录页的源码,可以参考这里:https://www.cnblogs.com/process-h/p/15522267.html 这节我们来看看如何自定义单表认 ...

  9. Spring Cloud Gateway自定义异常处理Exception Handler

    版本: Spring Cloud 2020.0.3 常见的方法有 实现自己的 DefaultErrorWebExceptionHandler 或 仅实现ErrorAttributes. 方法1: Er ...

随机推荐

  1. 爬虫之爬取电影天堂(request)

    #需要通过代码打开https://www.dytt8.net/网站,拿到网站内容 from urllib.request import urlopen #拿到urlopen import re con ...

  2. 从零开始学习springboot之热部署的配置

    各位看官大家好,博主之前因为毕业设计以及毕业旅游耽搁了好长一段时间没有更新博客了,从今天起又会慢慢开始学习啦. 今天主要是来学习springboot热部署的配置. 一. 热部署 我们通常在修改某些文件 ...

  3. 记一次上线部分docker不打日志的问题排查

    一次正常的上线,发了几台docker后,却发现有的机器打了info.log里面有日志,有的没有.排查问题开始: 第一:确认这台docker是否有流量进来,确认有流量进来. 第二:确认这台docker磁 ...

  4. C++7行代码实现求最大公约数

    最近在做奥赛题时碰到求最大公约数的问题,给出解决方案: int gcd(int a,int b){ int tmp = a%b; ){ return b; } else{ return gcd(b,t ...

  5. Go-cron定时任务

    1.cron(计划任务) 按照约定的时间,定时的执行特定的任务(job). cron 表达式 表达了这种约定. cron 表达式代表了一个时间集合,使用 6 个空格分隔的字段表示. 秒 分 时 日 月 ...

  6. linux常用命令示例汇总

    1.ping -c 3 -i 0.1 -W 1 -t 3 100.100.242.181 -c发包数目,-c 3三个 -i,发包间隔,-i 0.1,每隔0.1秒发一个包 -W,发包超时时间,-W 1, ...

  7. IOS系统

    苹果产品以前技术是很牛逼.但是,苹果的系统是IOS系统,是一个封闭系统,就是你只看的到程序看不到文件的存储位置,相当于说他们自己的软件或者要花钱的软件才可以在闭环系统里面通过苹果视频该软件导出来,祝2 ...

  8. Spring学习之旅(八)--SpringMVC请求参数

    现在我们已经完成了一个无参的接口了,但是应用中有很多需要携带参数的场景,我们来看看 ** SpringMVC** 对它的支持. 参数绑定 SpringMVC 提供了一种绑定机制,通过这个机制可以从请求 ...

  9. JVM(十三):后端编译优化

    JVM(十三):后端编译优化 在 JVM(一):源文件的转变 中我们介绍了 Java 中的前端优化,即将 Java 源代码转换为字节码文件.在本文中,我们将介绍字节码文件如何转换为本地机器码,并如何对 ...

  10. CSS3 translate导致字体模糊

    今日客户反馈,发现 使用了 translate会导致字体模糊. .media-body-box{ @media all and (min-width: 992px){ position: absolu ...