1. 结论
**
AuthenticationEntryPoint 用来解决匿名用户访问无权限资源时的异常
AccessDeineHandler 用来解决认证过的用户访问无权限资源时的异常
2. AuthenticationEntryPoint
AuthenticationEntryPoint 是 Spring Security Web 一个概念模型接口,顾名思义,他所建模的概念是:“认证入口点”。
它在用户请求处理过程中遇到认证异常时,被 ExceptionTranslationFilter 用于开启特定认证方案 (authentication schema) 的认证流程。
该接口只定义了一个方法 :
void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException;
这里参数 request 是遇到了认证异常 authException 用户请求,response 是将要返回给客户的相应,方法 commence 实现,也就是相应的认证方案逻辑会修改 response 并返回给用户引导用户进入认证流程。
当用户请求了一个受保护的资源,但是用户没有通过认证,那么抛出异常,AuthenticationEntryPoint.Commence(..)就会被调用。这个对应的代码在ExceptionTranslationFilter中,如下,当ExceptionTranslationFilter catch到异常后,就会间接调用AuthenticationEntryPoint。
public class ExceptionTranslationFilter extends GenericFilterBean {
private AuthenticationEntryPoint authenticationEntryPoint;
......
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
try {
chain.doFilter(request, response);
this.logger.debug("Chain processed normally");
} catch (IOException var9) {
throw var9;
} catch (Exception var10) {
......
this.handleSpringSecurityException(request, response, chain, (RuntimeException)ase);
}
}
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, RuntimeException exception) throws IOException, ServletException {
......
this.sendStartAuthentication(request, response, chain, (AuthenticationException)exception);
......
}
protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, AuthenticationException reason) throws ServletException, IOException {
SecurityContextHolder.getContext().setAuthentication((Authentication)null);
this.requestCache.saveRequest(request, response);
this.logger.debug("Calling Authentication entry point.");
this.authenticationEntryPoint.commence(request, response, reason);
}
......
匿名用户访问某个接口时
/**
* 认证失败处理类 返回未授权
* 用来解决匿名用户访问无权限资源时的异常
*/
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/javascript;charset=utf-8");
response.getWriter().print(JSONObject.toJSONString(RestMsg.error("没有访问权限!")));
}
}
3. AccessDeniedHandler
AccessDeniedHandler 仅适用于已通过身份验证的用户。未经身份验证的用户的默认行为是重定向到登录页面(或适用于正在使用的身份验证机制的任何内容)。
已经授权但是没有访问权限
/**
* 认证失败处理类 返回未授权
* 用来解决认证过的用户访问无权限资源时的异常
*/
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/javascript;charset=utf-8");
response.getWriter().print(JSONObject.toJSONString(RestMsg.error("没有访问权限!")));
}
}
4. 配置
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private CustomAccessDeniedHandler customAccessDeniedHandler;
// 省略部分代码
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 认证失败处理类
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(customAccessDeniedHandler);
}
// 省略部分代码
}