携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
前言
目前的登录接口,在账号密码不存在或错误的情况下,会直接返回 401 请求码异常。如图:
前端封装的 axios 拦截,适配最好请求码都是 200,然后根据返回的 code 进行判断,也就是正常返回数据,如下:
例如用户名密码错误
{
"code": 401,
"msg": "用户名密码错误",
"data": null
}
这样前端只需要判断 code 就能来进行提示不同格式 message 的信息。 同时也更好的判断后续的操作。
编写 JwtAuthenticationEntryPoint
文件:JwtAuthenticationEntryPoint.java
package com.example.auth.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.error("权限校验失败:{}", authException.getLocalizedMessage(), authException);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
LinkedHashMap<String, Object> resMap = new LinkedHashMap<>(4);
String msg = "用户未登录或者token失效";
int code = 0;
if (authException instanceof BadCredentialsException) {
code = 500;
msg = "用户名或密码错误!";
}
resMap.put("code", code);
resMap.put("msg", msg);
resMap.put("data", null);
writer.write(new ObjectMapper().writeValueAsString(resMap));
writer.flush();
writer.close();
}
}
更改安全配置类
默认情况下,Spring Security 提供的 BasicAuthenticationEntryPoint 会向客户端返回 401 Unauthorized 响应的完整页面。这种异常显示方式在 html 浏览器挺好,直接返回页面,不过,在 Restful 的情况下,不太适合。
我们现在来自定义一个异常返回端点,返回 Restful 风格的。
新建文件: JwtAuthenticationEntryPoint.java
package com.example.auth.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.error("权限校验失败:{}", authException.getLocalizedMessage(), authException);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
LinkedHashMap<String, Object> resMap = new LinkedHashMap<>(4);
String msg = "用户未登录或者token失效";
int code = 401;
if (authException instanceof BadCredentialsException) {
code = 500;
msg = "用户名或密码错误!";
}
resMap.put("code", code);
resMap.put("msg", msg);
resMap.put("data", null);
writer.write(new ObjectMapper().writeValueAsString(resMap));
writer.flush();
writer.close();
}
}
在文件 SecurityConfiguration.java 注入 Bean ->
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
public void setJwtAuthenticationEntryPoint(JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint) {
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
}
然后在 filterChain 方法中的 http 链式末尾增加如下配置 ->
http.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint);
开始测试
打开 postman,请求登录
现在我们使用错误的 token 来访问被保护的资源
符合前端需要的预期效果,可以根据 code 码直接走不同的逻辑
总结
- 自定义
AuthenticationEntryPoint返回 Restful 风格 - 安全配置类设置自定义
AuthenticationEntryPoint