AuthenticationEntryPoint
简介
AuthenticationEntryPoint
是Spring Security Web
一个概念模型接口,顾名思义,他所建模的概念是:“认证入口点”。
它在用户请求处理过程中遇到认证异常时,被ExceptionTranslationFilter
用于开启特定认证方案(authentication schema
)的认证流程。
该接口只定义了一个方法 :
void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException;
这里参数request
是遇到了认证异常authException
用户请求,response
是将要返回给客户的相应,方法commence
实现,也就是相应的认证方案逻辑会修改response
并返回给用户引导用户进入认证流程。
在该方法被调用前, ExceptionTranslationFilter
会做好如下工作 :
- 填充属性
HttpSession
,使用属性名称为AbstractAuthenticationProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY
AuthenticationEntryPoint
源代码
package org.springframework.security.web;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationEntryPoint {
/**
* Commences an authentication scheme.
*
* ExceptionTranslationFilter will populate the HttpSession
* attribute named
* AbstractAuthenticationProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY
* with the requested target URL before calling this method.
*
* Implementations should modify the headers on the ServletResponse as
* necessary to commence the authentication process.
*
* @param request that resulted in an AuthenticationException
* @param response so that the user agent can begin authentication
* @param authException that caused the invocation
*
*/
void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException;
}
Spring Security Web
内置AuthenticationEntryPoint
实现类
Spring Security Web
为AuthenticationEntryPoint
提供了一些内置实现 :
Http403ForbiddenEntryPoint
设置响应状态字为
403
,并非触发一个真正的认证流程。通常在一个预验证(pre-authenticated authentication
)已经得出结论需要拒绝用户请求的情况被用于拒绝用户请求。HttpStatusEntryPoint
设置特定的响应状态字,并非触发一个真正的认证流程。
LoginUrlAuthenticationEntryPoint
根据配置计算出登录页面
url
,将用户重定向到该登录页面从而开始一个认证流程。BasicAuthenticationEntryPoint
对应标准
Http Basic
认证流程的触发动作,向响应写入状态字401
和头部WWW-Authenticate:"Basic realm="xxx"
触发标准Http Basic
认证流程。DigestAuthenticationEntryPoint
对应标准
Http Digest
认证流程的触发动作,向响应写入状态字401
和头部WWW-Authenticate:"Digest realm="xxx"
触发标准Http Digest
认证流程。DelegatingAuthenticationEntryPoint
这是一个代理,将认证任务委托给所代理的多个
AuthenticationEntryPoint
对象,其中一个被标记为缺省AuthenticationEntryPoint
。
在spring security 自定义使用:
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationEntryPointImpl.class);
private static final long serialVersionUID = -8970718410437077606L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException {
int code = HttpStatus.UNAUTHORIZED;
String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
logger.error(msg);
ServletUtils.renderString(response, JSON.toJSONString(RestResponse.error(code, msg)));
}
}
附上工具类:
public class ServletUtils {
/**
* 获取String参数
*/
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取request
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}
/**
* 获取response
*/
public static HttpServletResponse getResponse() {
return getRequestAttributes().getResponse();
}
/**
* 获取session
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}
public static void setRequestAttributes(RequestAttributes attributes) {
RequestContextHolder.setRequestAttributes(attributes);
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string) {
try {
response.setStatus(200);
// 允许跨域
response.setHeader("Access-Control-Allow-Origin", "*");
// 允许自定义请求头token(允许head跨域)
response.setHeader("Access-Control-Allow-Headers", "Authorization, authorization,token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 是否是Ajax异步请求
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
return true;
}
String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) {
return true;
}
return false;
}
}
只要将我们自定的的类注入,然后配置到spring security 配置中:
/**
* 认证失败处理类
*/
@Autowired
private AuthenticationEntryPointImpl unauthorizedHandler;
效果如下: