package com.scsoft.scpt.common.filter;
import com.scsoft.scpt.common.exception.BusinessException;
import com.scsoft.scpt.common.utils.JwtUtils;
import com.scsoft.scpt.utils.StringUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
- @title: SSOAuthFilter
- @Description:
- @Author: zhaopengfei
- @copyright: 雪城软件有限公司
- All rights Reserved,Designed By Scsoft
- @CreateDate: 2020/7/27 11:33
- @Version: 1.0
*/
@Component("SSOAuthFilter")
public class SSOAuthFilter extends FormAuthenticationFilter {
private static final Logger logger = LoggerFactory.getLogger(SSOAuthFilter.class);
@Autowired
JwtUtils jwtUtil;
/**
* 判断token是否为空、过期
* shiro权限拦截核心方法 返回true允许访问resource,
* @param request
* @param response
* @param mappedValue
* @return
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
String token = getRequestToken((HttpServletRequest) request);
try {
// 检查 token 有效性
//ExpiredJwtException JWT已过期
//SignatureException JWT可能被篡改
Jwts.parser().setSigningKey(jwtUtil.getSecret()).parseClaimsJws(token).getBody();
} catch (Exception e) {
// 身份验证失败,返回 false 将进入onAccessDenied 判断是否登陆。
onLoginFail(response);
return false;
}
String username= getUserNameFromToken(token);
// 存入到 request 中,在后面的业务处理中可以使用
request.setAttribute(username, username);
return true;
}
/**
* 上面的方法如果返回false,则接下来会执行这个方法,如果返回为true,则不会执行这个方法
* 判断是否为登录url,进一步判断请求是不是post
*
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
return executeLogin(request, response);
} else {
return true;
}
} else {
onLoginFail(response);
return false;
}
}
/**
* 鉴定失败,返回错误信息
* @param token
* @param e
* @param request
* @param response
* @return
*/
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
try {
((HttpServletResponse) response).setStatus(HttpStatus.BAD_REQUEST.value());
response.getWriter().print("鉴定失败");
} catch (IOException e1) {
logger.error(e1.getMessage(), e1);
}
return false;
}
/**
* token 认证失败
*
* @param response
*/
private void onLoginFail(ServletResponse response) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
((HttpServletResponse) response).setStatus(HttpStatus.UNAUTHORIZED.value());
try {
response.getWriter().print("没有权限,请联系管理员授权");
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
/**
* 获取请求中的token,首先从请求头中获取,如果没有,则尝试从请求参数中获取
*
* @param request
* @return
*/
private String getRequestToken(HttpServletRequest request) {
//从header中获取token
String token = request.getHeader(jwtUtil.getHeader());
//如果header中不存在token,则从参数中获取token
if (StringUtils.isBlank(token)) {
token = request.getParameter(jwtUtil.getHeader());
}
//如果header中不存在token,则从cookies中获取token
if (StringUtils.isBlank(token)) {
// 从 cookie 获取 token
Cookie[] cookies = request.getCookies();
if (null == cookies || cookies.length == 0) {
return null;
}
for (Cookie cookie : cookies) {
if (cookie.getName().equals(jwtUtil.getHeader())) {
token = cookie.getValue();
break;
}
}
}
return token;
}
/**
* 根据 token 获取 userName
*
* @param token token
* @return userId
*/
private String getUserNameFromToken(String token) {
if (StringUtils.isBlank(token)) {
throw new BusinessException(HttpStatus.UNAUTHORIZED.value(),"无效 token");
}
Claims claims = jwtUtil.parseToken(token);
if (claims == null || jwtUtil.isTokenExpired(claims.getExpiration())) {
throw new BusinessException(HttpStatus.UNAUTHORIZED.value(),jwtUtil.getHeader() + "失效,请重新登录");
}
return claims.getSubject();
}
}