系列文章:
权限与认证: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 即可。简单来说,就这一句是关键。
评论