import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 权限拦截器,校验每次请求是否有权限 token有没有过期
*/
@Slf4j
public class TokenFilter extends AuthenticatingFilter {
@Value("${auth.white}")
private String[] whiteList;
@Value("${auth.open}")
private Integer authOpen;
@Autowired
private UserService userService;
@Autowired
private LoginService loginService;
@Autowired
private AuthViewService authViewService;
@Autowired
private UserTokenService userTokenService;
@Autowired
private SysDictionaryService sysDictionaryService;
@Autowired
private UserChangePwdService userChangePwdService;
@Autowired
private ResourceI18nService resourceI18nService;
/**
* 创建Token, 支持自定义Token
*/
@Override
protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
UserTokenCheckBO cookieUser = GetValueFromCookie.getInfoFromCookie(request.getCookies());
return new UserToken(cookieUser.getUserId(), cookieUser.getToken(),
cookieUser.getResTag(), cookieUser.getSystemId(),
cookieUser.getSystemTag(), cookieUser.getUsername(), cookieUser.getStationCode());
}
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {
if (null == authOpen || authOpen == 0) {
log.info("当前关闭校验");
return true;
}
HttpServletRequest request = (HttpServletRequest) servletRequest;
String uri = request.getRequestURI();
log.info("当前url是{}", uri);
if (!checkUrl(uri)) {
UserTokenCheckBO cookieUser = GetValueFromCookie.getInfoFromCookie(request.getCookies());
Long systemId = null;
if (StringUtils.isNotBlank(cookieUser.getSystemId()) &&
!cookieUser.getSystemId().equalsIgnoreCase("undefined")) {
systemId = Long.valueOf(cookieUser.getSystemId());
}
List<AuthViewBO> authViewBOS = authViewService.getWhiteList(cookieUser.getSystemTag(), systemId);
if (CollUtil.isNotEmpty(authViewBOS)) {
for (AuthViewBO auth : authViewBOS) {
if (null != auth.getUrl() && uri.contains(auth.getUrl())) {
return true;
}
if (null != cookieUser && StringUtils.isNotBlank(cookieUser.getResTag())
&& StringUtils.isNotBlank(auth.getResTag())
&& cookieUser.getResTag().equals(auth.getResTag())) {
return true;
}
}
}
} else {
return true;
}
return false;
}
private boolean checkUrl(String requestUri) {
requestUri = requestUri.replaceAll(DOUBLE_SLASH, SINGLE_SLASH);
if (null != whiteList && whiteList.length > 0) {
for (String white : whiteList) {
if (requestUri.endsWith(white)) {
return true;
}
}
}
return requestUri.contains("/login") || requestUri.contains("/logout")
|| requestUri.contains("/swagger-ui") || requestUri.contains("/me/password")
|| requestUri.contains("/webjars/") || requestUri.contains("/api-docs/")
|| requestUri.contains("swagger-resources/") || requestUri.contains("/v2/")
|| requestUri.contains("/forward/message/");
}
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
if (null == authOpen || authOpen == 0) {
log.info("当前关闭校验");
return true;
}
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setCharacterEncoding("UTF-8");
UserTokenCheckBO cookieUser = GetValueFromCookie.getInfoFromCookie(request.getCookies());
String ipAddress = IpAddressUtil.getIpAddress(request);
String langStr = sysDictionaryService.getCurUseSystemLang(ipAddress);
log.info("shiro校验:当前用户cookie中信息{}", cookieUser);
if (StringUtils.isBlank(cookieUser.getUserId()) ||
StringUtils.isBlank(cookieUser.getToken())) {
Map<String, Object> result = new HashMap<>();
result.put("returnCode", AuthErrorCodes.NOT_LOGIN.exception().getCode());
result.put("returnUserMsg",
getMsg(AuthErrorCodes.NOT_LOGIN.exception().getMsg(), langStr));
httpResponse.getWriter().print(JSON.toJSONString(result));
log.info("shiro校验:当前用户未登录{}", cookieUser);
return false;
}
UserTokenExtBO userTokenBO = userService.getUserWithTokenById(cookieUser.getUserId());
userTokenBO.setUsername(
(null != userTokenBO.getUsername() && userTokenBO.getUsername().contains(";"))
? userTokenBO.getUsername().split(";")[0] : userTokenBO.getUsername());
log.info("当前获取用户信息为{}", userTokenBO);
if (null == userTokenBO || null == userTokenBO.getUserId()) {
Map<String, Object> result = new HashMap<>();
result.put("returnCode", AuthErrorCodes.USER_CLOSE_NULL.exception().getCode());
result.put("returnUserMsg",
getMsg(AuthErrorCodes.USER_CLOSE_NULL.exception().getMsg(), langStr));
httpResponse.getWriter().print(JSON.toJSONString(result));
log.info("shiro校验:根据cookie的userId用户不存在或者已停用{}", userTokenBO);
return false;
}
if (userTokenBO.isExpire()) {
Map<String, Object> result = new HashMap<>();
result.put("returnCode", AuthErrorCodes.USER_EXPIRED_ERROR.exception().getCode());
result.put("returnUserMsg",
getMsg(AuthErrorCodes.USER_EXPIRED_ERROR.exception().getMsg(), langStr));
httpResponse.getWriter().print(JSON.toJSONString(result));
log.info("shiro校验:根据cookie的userId获取当前用户但是已经过期{}", userTokenBO);
return false;
}
if (null == userTokenBO.getToken() || !userTokenBO.getToken().equals(cookieUser.getToken())) {
Map<String, Object> result = new HashMap<>();
result.put("returnCode", AuthErrorCodes.LOGIN_REPEAT.exception().getCode());
result.put("returnUserMsg",
getMsg(AuthErrorCodes.LOGIN_REPEAT.exception().getMsg(), langStr));
httpResponse.getWriter().print(JSON.toJSONString(result));
log.info("shiro校验:根据cookie的userId获取当前用户TOKEN不一致{}", userTokenBO);
return false;
}
Long userId = Long.valueOf(cookieUser.getUserId());
if (userChangePwdService.isExpire(userId,userTokenBO.getClientId())) {
loginService.logout(
UserWithTerminalReqBO.builder()
.userId(userId)
.username(userTokenBO.getUsername())
.systemId(cookieUser.getSystemId())
.terminal(cookieUser.getTerminal())
.build(),
"密码失效",
false);
Map<String, Object> result = new HashMap<>();
result.put("returnCode", AuthErrorCodes.USER_PWD_EXPIRE.exception().getCode());
result.put("returnUserMsg",
getMsg(AuthErrorCodes.USER_PWD_EXPIRE.exception().getMsg(), langStr));
httpResponse.getWriter().print(JSON.toJSONString(result));
log.info("shiro校验:当前用户密码失效{}", userTokenBO);
return false;
}
if (userTokenBO.getUsername().equals(SUPER_USER)) {
log.info("当前超级用户不需要限制");
userTokenService.updateTime(userId);
return true;
}
if (StringUtils.isNotBlank(cookieUser.getResTag())) {
if (!userService.hasTheRight(cookieUser.getSystemId(), Long.valueOf(cookieUser.getUserId()), cookieUser.getResTag())) {
Map<String, Object> result = new HashMap<>();
result.put("returnCode", AuthErrorCodes.NO_RIGHT.exception().getCode());
result.put("returnUserMsg",
getMsg(AuthErrorCodes.NO_RIGHT.exception().getMsg(), langStr));
httpResponse.getWriter().print(JSON.toJSONString(result));
log.info("shiro校验:当前用户没有权限{}", cookieUser);
return false;
}
}
userTokenService.updateTime(userId);
return true;
}
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest servletResponse, ServletResponse servletRequest) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setCharacterEncoding("UTF-8");
HttpServletRequest request = (HttpServletRequest) servletRequest;
try {
Map<String, Object> result = new HashMap<>();
result.put("returnCode", AuthErrorCodes.LOGIN_FAIL.exception().getCode());
result.put("returnUserMsg",
getMsg(AuthErrorCodes.LOGIN_FAIL.exception().getMsg(),
sysDictionaryService.getCurUseSystemLang(IpAddressUtil.getIpAddress(request))));
httpResponse.getWriter().print(JSON.toJSONString(result));
} catch (IOException ioException) {
log.info("shiro校验:当前shiro解析出现了问题{}", e, e);
}
return false;
}
private String getMsg(String message, String lang) {
return resourceI18nService.getResNameByLange(lang, message);
}
}
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Sha512Hash;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
@Configuration
@DependsOn({ "userService", "authViewService"})
public class AuthConfig {
@Autowired
private UserService userService;
@Autowired
private AuthViewService authViewService;
@Value("${session.update:300000}")
private Integer sessionUpdateTime;
@Bean
public TokenFilter tokenFilter(){
return new TokenFilter();
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashMatcher = new HashedCredentialsMatcher();
hashMatcher.setHashAlgorithmName(Sha512Hash.ALGORITHM_NAME);
hashMatcher.setStoredCredentialsHexEncoded(false);
hashMatcher.setHashIterations(1);
return hashMatcher;
}
@Bean
public Realm realm() {
return new AuthRealm();
}
@Bean
public ShiroService shiroService() {
return new ShiroServiceImpl();
}
@Bean
public DefaultWebSecurityManager securityManager(SessionManager sessionManager) {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
defaultSecurityManager.setRealm(realm());
defaultSecurityManager.setSessionManager(sessionManager);
return defaultSecurityManager;
}
@Bean
public SessionManager sessionManager(AuthSessionDao sessionDao) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager() {
@Override
public void touch(SessionKey key) throws InvalidSessionException {
Session session = doGetSession(key);
if (session != null) {
long oldTime = session.getLastAccessTime().getTime();
session.touch(); // 更新访问时间
long newTime = session.getLastAccessTime().getTime();
if (newTime - oldTime >sessionUpdateTime ) { // 如果两次访问的时间间隔大于5分钟,主动持久化Session
onChange(session);
}
}
}
};
sessionManager.setSessionDAO(sessionDao);
return sessionManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterChainDefinition(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>(2);
filters.put("tokenFilter", new TokenFilter());
shiroFilterFactoryBean.setFilters(filters);
shiroFilterFactoryBean.setFilterChainDefinitionMap(
shiroService().loadFilterChainDefinitionMap());
//authc表示需要验证身份才能访问,还有一些比如anon表示不需要验证身份就能访问等。
shiroFilterFactoryBean.setLoginUrl("/login");
return shiroFilterFactoryBean;
}
}
@Slf4j
//@Component
public class AuthRealm extends AuthorizingRealm {
@Lazy
@Autowired
private UserService userService;
@Autowired
private UserTokenService userTokenService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UserTokenExtBO userTokenExtBO = new UserTokenExtBO();
if (authenticationToken instanceof UserToken) {
log.info("当前是userToken");
UserToken token = (UserToken) authenticationToken;
if (null == token || StringUtils.isBlank(token.getUserId())) {
throw new UnknownAccountException("No account found for admin ");
}
userTokenExtBO = userService.getUserWithTokenById(token.getUserId());
if (userTokenExtBO == null) {
throw new UnknownAccountException("No account found for admin [" + Long.valueOf(token.getUserId()) + "]");
}
return new SimpleAuthenticationInfo(userTokenExtBO, token.getToken(), getName());
} else {
AuthUserToken wesUserToken = (AuthUserToken) authenticationToken;
if (wesUserToken.getUsername() == null) {
throw new AccountException("Null usernames are not allowed by this realm.");
}
String[] username = wesUserToken.getUsername().split(";");
userTokenExtBO = userService.getUserWithTokenByName(username[0], username.length > 1 ? username[1] : "");
if (userTokenExtBO == null) {
throw new UnknownAccountException("No account found for admin [" + username[0] + "]");
}
SimpleAuthenticationInfo authenticationInfo =
new SimpleAuthenticationInfo(userTokenExtBO, userTokenExtBO.getPassword(), getName());
if (userTokenExtBO.getSalt() != null) {
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userTokenExtBO.getSalt()));
}
return authenticationInfo;
}
}
@Override
public boolean supports(AuthenticationToken token) {
var superRs = super.supports(token);
if (!superRs) {
return token instanceof UserToken;
}
return true;
}
}