由于最近遇到了新问题,还折磨了我两天,所以这里就简单的记录一下⑧
错误集中处理
由于系统需要,所以为项目添加了一个错误集中处理配置
前情提要
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
的相关文章,我只能找到这样一篇文章,稍微提到了一下,也没去官方文档去查,不过大概了解它的功能了,就是一个认证系统,不过还是存疑,以后有机会可以再去官方文档搜搜。
赶着下班,今天就草草写到这了。