关于异常处理以及针对spring security oauth 2的401错误进行页面跳转

本文介绍如何在SpringBoot项目中配置错误集中处理,包括404、500等HTTP状态码的自定义页面显示,以及解决OAuth2认证中invalid_token问题的方法。通过实现ErrorPageConfig和AuthExceptionEntryPoint,实现对特定错误的统一处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于最近遇到了新问题,还折磨了我两天,所以这里就简单的记录一下⑧

错误集中处理

由于系统需要,所以为项目添加了一个错误集中处理配置
前情提要

spring boot : 2.0.3.RELEASE

参考文章

首先根据spring boot版本的不同,以1.4.0为界是有不同的配置方式的,这里由于用的是2.0.3.RELEASE,所以配置如下。

package com.yubotao.springsecurityoauth2.config;

import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;



/**
 * @Auther: yubt
 * @Description:
 * @Date: Created in 17:23 2018/10/10
 * @Modified By:
 */
@Component
public class ErrorPageConfig implements ErrorPageRegistrar {

    @Override
    public void registerErrorPages(ErrorPageRegistry registry){
        ErrorPage[] errorPages = new ErrorPage[]{
                new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"),
                new ErrorPage(Throwable.class, "/error/500")
        };
        registry.addErrorPages(errorPages);

    }

}

接着加一个进行跳转的Controller

package com.yubotao.springsecurityoauth2.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @Auther: yubt
 * @Description:
 * @Date: Created in 17:17 2018/10/10
 * @Modified By:
 */
@Controller
@RequestMapping("/error")
public class ErrorController {

    @RequestMapping(value = "/401", method = RequestMethod.GET)
    public String error_401(){
        return "error_401";
    }

    @RequestMapping(value = "/404", method = RequestMethod.GET)
    public String error_404(){
        return "error_404";
    }

    @RequestMapping(value = "/500", method = RequestMethod.GET)
    public String error_500(){
        return "error_500";
    }

}

然后放一个页面吧,其他的都一样
error_404.html

<!DOCTYPE html>
<html>
<head>

</head>

<body>
<h1>404</h1>
<h3>抱歉,无法找到网页</h3>
</body>
</html>

spring security oauth 2 的401处理(invalid_token)

开始我们使用了上面的那种异常集中处理,我开始以为可以把401错误也纳入其中,但是经过尝试之后发现这种方式是行不通的,因为当出现401报错的时候,返回的是一个xml形式的,总之就很烦,然后这个地方我用了1天的时间才找到比较好的解决办法。
在这里插入图片描述

最开始的想法是用过滤器,应该是可以做的,但是我没做,一个是网上相关资料较少,再就是想看看有没有其他的方式解决。

后来用尝试了使用对oauth 2的资源服务器进行配置登陆页面的方式,就是如下这种方式

 @Override
        public void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                    .and()
                    .requestMatchers().anyRequest()
                    .and()
                    .anonymous()
                    .and()
                    .formLogin().loginPage("/login")
                    .and()
                    .authorizeRequests()
                    // or可以通过access_token访问,但是and不行;经过测试,应该是hasRole()方法出了问题,这里无法通过
//                    .antMatchers("/product/**").access("#oauth2.hasScope('select') and  hasRole('ROLE_ADMIN')")
                    .antMatchers("/order/**").authenticated();  // 配置order访问控制,必须认证过后才可以访问
            // @formatter:on
        }

这种情况貌似是失败了,无奈之下,只能继续寻找解决方法,果然让我找到了,可以看到这个文章,虽然效果不是我想要的,但是是可以借鉴的。

所以其实我们只需要定义一个AuthExceptionEntryPoint

package com.yubotao.springsecurityoauth2.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Auther: yubt
 * @Description:
 * @Date: Created in 11:36 2018/10/11
 * @Modified By:
 */
public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {

    @Value("${server.url}")
    private  String serverUrl;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException)
            throws ServletException {

//        Map map = new HashMap();
//        map.put("error", "401");
//        map.put("message", "token过期,请重新登陆");
//        map.put("path", request.getServletPath());
//        map.put("timestamp", String.valueOf(new Date().getTime()));
//        response.setContentType("application/json");
//        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        try {
//            ObjectMapper mapper = new ObjectMapper();
//            mapper.writeValue(response.getOutputStream(), map);
            System.out.println("进入Entry方法");
            response.sendRedirect(serverUrl + "/error/401");
        } catch (Exception e) {
            throw new ServletException();
        }
    }

}

开始的时候我以为这种方式也不行,因为我没有注掉那些代码,就进行了重定向,结果还是报错了,并且发现这个方法进入了两次,然后同事说了依据可能是response.setContentType("application/json");这句的问题,然后我就把上面的代码注掉,果然就可以正确重定向了。

这样,我们就把这个invalid_token的问题给解决了。
效果如下
当我请求http://localhost:8080/order/1时,由于需要权限,但是我并没有登陆,所以就会重定向到这个页面
在这里插入图片描述

而关于AuthenticationEntryPoint的相关文章,我只能找到这样一篇文章,稍微提到了一下,也没去官方文档去查,不过大概了解它的功能了,就是一个认证系统,不过还是存疑,以后有机会可以再去官方文档搜搜。

赶着下班,今天就草草写到这了。

Github项目地址

### 配置页面过滤和拦截 为了在Spring Security OAuth2客户端中实现页面过滤或拦截功能,可以利用`HttpSecurity`对象来定义安全策略。通过自定义配置类并扩展`WebSecurityConfigurerAdapter`(虽然此适配器已被标记为过时),或者直接使用Java Config的方式来进行更灵活的安全设置。 #### 自定义安全配置类 创建一个新的配置类用于覆盖默认行为,并在此处指定哪些URL路径应该被保护起来,以及访问这些资源所需的权限级别: ```java @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login", "/oauth2/**").permitAll() // 允许所有人访问登录页和其他OAuth相关链接 .anyRequest().authenticated(); // 所有其他请求都需要身份验证 http.oauth2Login(); // 启用OAuth2登录机制 // 添加额外的过滤器或其他安全措施... http.exceptionHandling().accessDeniedPage("/error/403"); // 设置未授权错误页面 } } ``` 上述代码片段展示了如何允许特定路径无需认证即可访问,而其余所有请求则需经过身份验证才能继续处理[^1]。 对于进一步增强安全性,还可以引入更多的HTTP安全特性,比如CSRF防护、会话管理等。此外,如果希望对某些操作实施细粒度控制,则可以通过编写自己的方法级安全注解来达成目的。 #### 使用Filter链进行定制化拦截 除了调整全局性的安全规则外,有时还需要针对具体的应用场景执行特殊的逻辑判断。这时就可以考虑向现有的Servlet Filter链条里加入新的处理器实例。例如,在用户成功完成OAuth流程之后自动重定向到之前尝试进入的目标地址;又或者是记录下每一次成功的登陆事件以便后续审计之用。 要实现这一点,可以在`configure()`函数内部调用`.addFilterBefore()` 或 `.addFilterAfter()` 方法来自定义位置插入所需filter: ```java http.addFilterBefore(new CustomAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class); // 或者 http.addFilterAfter(new PostLoginRedirectFilter(), OAuth2LoginAuthenticationFilter.class); ``` 这里假设已经有一个名为 `CustomAuthenticationProcessingFilter` 的类实现了必要的接口并且完成了相应的初始化工作。同样地,`PostLoginRedirectFilter` 是用来处理登出后的跳转逻辑的一个简单例子[^2]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值