系列文章:
权限与认证:JWT
权限与认证:JWT 实践
权限与认证:基于 JWT 的授权实现
一 概述
权限与认证:基于 JWT 的授权实现中提到了登录授权时的 token 信息拦截和解析,并在验证通过后进行用户信息相关的参数注入。但在真实业务中还会经常遇到这样的需求,授权验证失败,我们希望返回 401 的 HTTP 错误码,对应的,可能还有 401、302 等等其他需求。这里就通过一个示例来进行说明。
二 HTTP 常用错误码
这相关的资料百度一搜到处都是,这里就不再重复描述了。不过会提取出鉴权相关的错误码如下:
2.1 401-unauthorized
原因:您的 web 服务器开启了密码验证,客户端在请求的时候需要填入用户名和密码,只有输入正确的用户名和密码才能正常访问。
解决:输入正确的用户名和密码;关闭 web 服务器的密码验证功能。
2.2 403-Forbidden
原因:禁止访问,请求是合法的,但是却因为服务器配置规则而拒绝响应客户端请求,此类问题一般为服务器或服务权限配置不当导致。
解决:确保主页文件存在,如 index.php 或 index.html;确保 web 服务器运行用户和站点的目录权限一致,比如你的 nginx 运行用户为 www,你需要确保你的站点目录的所有者为 www。
三 HttpServletResponse 中的错误码定义
javax.servlet.http 包中的 HttpServletResponse 是一个接口,继承自 ServletResponse。其中定义了从 100 到 505 的 HTTP 错误码:
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
复制代码
四 实现示例
改动点在 AuthenticationInterceptor.java,在拦截 token 信息并鉴权时,加上错误 token 时的返回信息:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
String token = request.getHeader(TokenUtil.SAFETY_TOKEN_KEY);
if (!(object instanceof HandlerMethod)) {
return true;
}
if (token == null) {
return print(request, response);
}
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("xxxxxx")).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
logger.error("错误的token : " + e.getMessage());
return print(request, response);
}
复制代码
关键就是在 print(request, response)方法,内容如下:
private boolean print(HttpServletRequest request, HttpServletResponse response) {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try (
OutputStream out = response.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out, "utf-8"))
) {
pw.print("{\"errorMessage\":\"token过期\"}");
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
复制代码
其实非常简单。使用 OutputStream 打印 token 消息,并在 response 中设置 status 为 HttpServletResponse.SC_UNAUTHORIZED 即可。简单来说,就这一句是关键。
评论