项目结构

增加全局异常配置
1/**
2 * @Description GlobaException 全局的异常配置
3 * @Author YiLong Wu
4 * @Date 2020-03-11 22:28
5 * @Version 1.0.0
6 */
7@RestControllerAdvice
8public class GlobalException {
9
10 /**
11 * 处理用户名密码错误的异常
12 * @return
13 */
14 @ExceptionHandler({UnknowUsenameAndPasswordException.class})
15 @ResponseStatus
16 public ResponseError unknowUsenameAndPasswordException() {
17 return new ResponseError(HttpStatus.INTERNAL_SERVER_ERROR.value(),"用户名或密码错误");
18 }
19
20 /**
21 * 处理权限不足的异常
22 * @param e
23 * @return
24 */
25 @ExceptionHandler(AuthorizationException.class)
26 @ResponseStatus(HttpStatus.FORBIDDEN)
27 public ResponseError authorizationException(AuthorizationException e) {
28 return new ResponseError(HttpStatus.FORBIDDEN.value(),"你没有权限访问");
29 }
30
31 /**
32 * 处理token的异常
33 * @return
34 */
35 @ExceptionHandler(InvalidTokenException.class)
36 @ResponseStatus
37 public ResponseError invalidTokenException() {
38 return new ResponseError(HttpStatus.INTERNAL_SERVER_ERROR.value(),"不合法的token");
39 }
40
41 /**
42 * 处理用户账户异常
43 * @return
44 */
45 @ExceptionHandler(UnknownAccountException.class)
46 @ResponseStatus
47 public ResponseError unknownAccountException() {
48 return new ResponseError(HttpStatus.INTERNAL_SERVER_ERROR.value(),"账户异常");
49 }
50}
相关解析:
@RestControllerAdvice要结合ExceptionHandler一起使用,增加@ResponseStatus,是为了更友好的响应给客户端
增加JwtFilter过滤器用于认证过滤
1/**
2 * @ClassName JWTFilter
3 * @Description
4 * @Author yilongwu
5 * @DATE 2020-03-12 17:57
6 * @Version 1.0.0
7 **/
8@Slf4j
9public class JWTFilter extends BasicHttpAuthenticationFilter {
10
11 // 是否允许访问
12 @SneakyThrows
13 @Override
14 protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
15 log.info("*********进入isAccessAllowed********");
16 response.setCharacterEncoding("utf-8");
17 response.setContentType("application/json");
18 ResponseError responseError = new ResponseError();
19 if(isLoginAttempt(request,response)) {
20 try {
21 executeLogin(request, response);
22 return true;
23 } catch (Exception e) {
24 log.info("****InvalidTokenException****");
25 if(e instanceof InvalidTokenException) {
26 request.getRequestDispatcher("/invalidToken").forward(request,response);
27 }else if(e instanceof UnknownAccountException) {
28 request.getRequestDispatcher("/unknownAccount").forward(request,response);
29 }
30 return true;
31 }
32 }
33
34 // 当没有带token访问时
35 responseError.setCode(401);
36 responseError.setMessage("没有访问凭证");
37 ObjectMapper objectMapper = new ObjectMapper();
38 response.getWriter().write(objectMapper.writeValueAsString(responseError));
39 return false;
40 }
41
42 // 执行登录
43 @Override
44 protected boolean executeLogin(ServletRequest request, ServletResponse response) {
45 log.info("************进入executeLogin*******");
46 String token = ((HttpServletRequest) request).getHeader("Authorization");
47 // 自定义的认证token
48 JWTToken jwtToken = new JWTToken(token);
49 getSubject(request,response).login(jwtToken);
50 return true;
51 }
52
53 // 是否接受登录
54 @Override
55 protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
56 log.info("*******************进入isLoginAttempt********");
57 String token = ((HttpServletRequest) request).getHeader("Authorization");
58 return StringUtils.isNotBlank(token) && token.startsWith("Bearer ");
59 }
60}
shiro结合jwt认证异常问题
自定义异常要继承AuthenticationException,要不在自定义全局异常时控制台会出现
1Authentication failed for token submission [JWTToken(token=Bearer eyJhbGciOiJIUzUxMiJ9.eyJuYW1lIjoiYWRtaW4iLCJleHAiOjE1ODQ0MjU2ODd9.7qqO9TjI8RbS12FELNI8n5OcnQABezfv6AtbbbZDGy7bwYfu3PH1r9RKOHVEBlLarI7w47QhU-kmm8GON0g6n)]. Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException).
为什么会出现?在认证抛出异常的地方debug进去看到如下
1 public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
2
3 if (token == null) {
4 throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");
5 }
6
7 log.trace("Authentication attempt received for token [{}]", token);
8
9 AuthenticationInfo info;
10 try {
11 info = doAuthenticate(token);
12 if (info == null) {
13 String msg = "No account information found for authentication token [" + token + "] by this " +
14 "Authenticator instance. Please check that it is configured correctly.";
15 throw new AuthenticationException(msg);
16 }
17 } catch (Throwable t) {
18 AuthenticationException ae = null;
19 if (t instanceof AuthenticationException) {
20 ae = (AuthenticationException) t;
21 }
22 if (ae == null) {
23 //Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more
24 //severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate:
25 String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " +
26 "error? (Typical or expected login exceptions should extend from AuthenticationException).";
27 ae = new AuthenticationException(msg, t);
28 if (log.isWarnEnabled())
29 log.warn(msg, t);
30 }
31 try {
32 notifyFailure(token, ae);
33 } catch (Throwable t2) {
34 if (log.isWarnEnabled()) {
35 String msg = "Unable to send notification for failed
36 authentication attempt - listener error?. " +
37 "Please check your AuthenticationListener implementation(s). Logging sending exception " +
38 "and propagating original AuthenticationException instead...";
39 log.warn(msg, t2);
40 }
41 }
42
43
44 throw ae;
45 }
46
47 log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info);
48
49 notifySuccess(token, info);
50
51 return info;
52 }
很明显就看到了如果抛出的异常不是AuthenticationException的子类,那么就会出现这个消息
还有就是这个时候下面的代码捕获的异常已经变成AuthenticationException,所以会无法dispatcher.
1 if(isLoginAttempt(request,response)) {
2 try {
3 boolean b = executeLogin(request, response);
4 return true;
5 } catch (Exception e) {
6 log.info("****InvalidTokenException");
7 if(e instanceof InvalidTokenException) {
8 request.setAttribute("invalidToken","不合法的token");
9 request.getRequestDispatcher("/invalidToken").forward(request,response);
10 return true;
11 }
12
13 }
14 }
最后
项目的github地址:springboot-shiro-jwt