Spring Security关于异常的处理

  • Post author:
  • Post category:其他

Spring Security系列文章目录

关于Spring Security
Spring Security详解(1)
Spring Security详解(2)
Spring Security关于异常的处理


前言

前面三期已经介绍完了Spring Security的详细开发流程,这期主要解决Spring Security异常的处理。

提示:以下是本篇文章正文内容,部分代码可供参考

一、处理异常

在登录时,可能出现:

  • 用户名错误:BadCredentialsException
  • 密码错误:BadCredentialsException
  • 账号被禁用:DisabledException

在访问时,可能出现:

  • 无此权限:AccessDeniedException

以上异常都可以由统一处理异常的机制进行处理,关于统一处理异常的机制,参考专栏系列文章之MVC设计思想。则先在ServiceCode中添加对应的业务状态码:

public interface ServiceCode {
    
    Integer OK = 20000;               //成功

    Integer ERR_BAD_REQUEST = 40000;  //请求参数格式错误

    Integer ERR_UNAUTHORIZED = 40100;     //未授权登录

    Integer ERR_UNAUTHORIZED_DISABLE = 40101;     //未授权登录

    Integer ERR_FORBIDDEN = 40300;  //无权限访问

    Integer ERR_NOT_FOUND = 40400;  //相关资源或数据不存在

    Integer ERR_CONFLICT = 40900;   //数据冲突,例如尝试添加不允许重复的数据

    Integer ERR_INSERT = 50001;     //插入数据时的错误

    Integer ERR_DELETE = 50002;     //删除数据时的错误

    Integer ERR_UPDATE = 50003;     //修改数据时的错误

    Integer ERR_INTERNAL_SERVER_ERROR = 50000;    //服务器内部错误,通常是未确定的异常类型

    Integer ERR_JWT_PARSE = 60000;  //解析jwt失败:格式错误,或签名错误

    Integer ERR_JWT_EXPIRED = 60001;  //解析jwt失败:过期
}

然后,在统一处理异常的类中,添加对相关异常的处理:

@ExceptionHandler
public JsonResult<Void> handleBadCredentialsException(BadCredentialsException e) {
    String message = "登录失败,用户名或密码错误!";
    log.debug("处理BadCredentialsException:{}", message);
    return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED, message);
}

@ExceptionHandler
public JsonResult<Void> handleDisabledException(DisabledException e) {
    String message = "登录失败,此账号已禁用!";
    log.debug("处理DisabledException:{}", message);
    return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED_DISABLED, message);
}

@ExceptionHandler
public JsonResult<Void> handleAccessDeniedException(AccessDeniedException e) {
    String message = "访问失败,当前登录的账号无此权限!";
    log.debug("处理AccessDeniedException:{}", message);
    return JsonResult.fail(ServiceCode.ERR_FORBIDDEN, message);
}

另外,在解析JWT的过程中,也可能出现异常,由于解析JWT是在过滤器中进行的,如果出现异常,不会被统一处理异常的机制获取得到(因为过滤器执行的时间点太早),所以,只能在过滤器中自行处理异常,例如:


//设置响应结果的文档类型
response.setContentType("application/json; charset=utf-8");
// 尝试解析JWT
Claims claims = null;
try {
    claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
} catch (MalformedJwtException e) {
    log.warn("解析JWT失败:{}:{}", e.getClass().getName(), e.getMessage());
    JsonResult<Void> jsonResult = JsonResult.fail(
            ServiceCode.ERR_JWT_PARSE, "无法获取到有效的登录信息,请重新登录!");
    String jsonResultString = JSON.toJSONString(jsonResult);
    PrintWriter writer = response.getWriter();
    writer.println(jsonResultString);
    writer.close();
    return;
} catch (SignatureException e) {
    log.warn("解析JWT失败:{}:{}", e.getClass().getName(), e.getMessage());
    JsonResult<Void> jsonResult = JsonResult.fail(
            ServiceCode.ERR_JWT_PARSE, "无法获取到有效的登录信息,请重新登录!");
    String jsonResultString = JSON.toJSONString(jsonResult);
    PrintWriter writer = response.getWriter();
    writer.println(jsonResultString);
    writer.close();
    return;
} catch (ExpiredJwtException e) {
    log.warn("解析JWT失败:{}:{}", e.getClass().getName(), e.getMessage());
    JsonResult<Void> jsonResult = JsonResult.fail(
            ServiceCode.ERR_JWT_EXPIRED, "登录信息已过期,请重新登录!");
    String jsonResultString = JSON.toJSONString(jsonResult);
    PrintWriter writer = response.getWriter();
    writer.println(jsonResultString);
    writer.close();
    return;
} catch (Throwable e) {
    log.warn("解析JWT失败:{}:{}", e.getClass().getName(), e.getMessage());
    JsonResult<Void> jsonResult = JsonResult.fail(
            ServiceCode.ERR_JWT_PARSE, "无法获取到有效的登录信息,请重新登录!");
    String jsonResultString = JSON.toJSONString(jsonResult);
    PrintWriter writer = response.getWriter();
    writer.println(jsonResultString);
    writer.close();
    return;
}

总结

提示:这里对文章进行总结:

OK,至此整个通过Spring security处理开发过程中用户认证和授权的流程结束。


版权声明:本文为weixin_43816557原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。