package com.cloudroam.common.interceptor; import com.cloudroam.service.GroupService; import com.cloudroam.service.UserService; import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.InvalidClaimException; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.Claim; import io.github.talelin.autoconfigure.bean.MetaInfo; import io.github.talelin.autoconfigure.exception.AuthenticationException; import io.github.talelin.autoconfigure.exception.AuthorizationException; import io.github.talelin.autoconfigure.exception.NotFoundException; import io.github.talelin.autoconfigure.exception.TokenInvalidException; import io.github.talelin.autoconfigure.interfaces.AuthorizeVerifyResolver; import io.github.talelin.core.token.DoubleJWT; import com.cloudroam.common.LocalUser; import com.cloudroam.model.PermissionDO; import com.cloudroam.model.UserDO; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.List; import java.util.Map; import java.util.regex.Pattern; /** * @author * @author * 鉴权实现类 */ @Component public class AuthorizeVerifyResolverImpl implements AuthorizeVerifyResolver { public static final String AUTHORIZATION_HEADER = "Authorization"; public static final String BEARER_PATTERN = "^Bearer$"; @Autowired private DoubleJWT jwt; @Autowired private UserService userService; @Autowired private GroupService groupService; @Value("${lin.file.domain}") private String domain; @Value("${lin.file.serve-path:assets/**}") private String servePath; @Override public boolean handleLogin(HttpServletRequest request, HttpServletResponse response, MetaInfo meta) { String tokenStr = verifyHeader(request); Map claims; try { claims = jwt.decodeAccessToken(tokenStr); } catch (TokenExpiredException e) { throw new io.github.talelin.autoconfigure.exception.TokenExpiredException(10051); } catch (AlgorithmMismatchException | SignatureVerificationException | JWTDecodeException | InvalidClaimException e) { throw new TokenInvalidException(10041); } return getClaim(claims); } @Override public boolean handleGroup(HttpServletRequest request, HttpServletResponse response, MetaInfo meta) { handleLogin(request, response, meta); UserDO user = LocalUser.getLocalUser(); if (verifyAdmin(user)) { return true; } Integer userId = user.getId(); String permission = meta.getPermission(); String module = meta.getModule(); List permissions = userService.getUserPermissions(userId); boolean matched = permissions.stream().anyMatch(it -> it.getModule().equals(module) && it.getName().equals(permission)); if (!matched) { throw new AuthenticationException(10001); } return true; } @Override public boolean handleAdmin(HttpServletRequest request, HttpServletResponse response, MetaInfo meta) { handleLogin(request, response, meta); UserDO user = LocalUser.getLocalUser(); if (!verifyAdmin(user)) { throw new AuthenticationException(10001); } return true; } @Override public boolean handleRefresh(HttpServletRequest request, HttpServletResponse response, MetaInfo meta) { String tokenStr = verifyHeader(request); Map claims; try { claims = jwt.decodeRefreshToken(tokenStr); } catch (TokenExpiredException e) { throw new io.github.talelin.autoconfigure.exception.TokenExpiredException(10052); } catch (AlgorithmMismatchException | SignatureVerificationException | JWTDecodeException | InvalidClaimException e) { throw new TokenInvalidException(10042); } return getClaim(claims); } @Override public boolean handleNotHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) { return true; } @Override public void handleAfterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // 记住:很重要,请求结束后,一定要清理 ThreadLocal 中的用户信息 LocalUser.clearLocalUser(); } private boolean getClaim(Map claims) { if (claims == null) { throw new TokenInvalidException(10041); } int identity = claims.get("identity").asInt(); UserDO user = userService.getById(identity); if (user == null) { throw new NotFoundException(10021); } String avatarUrl; final String protocolPrefix = "http"; if (user.getAvatar() == null) { avatarUrl = null; } else if (user.getAvatar().startsWith(protocolPrefix)) { avatarUrl = user.getAvatar(); } else { avatarUrl = domain + servePath.split("/")[0] + "/" + user.getAvatar(); } user.setAvatar(avatarUrl); LocalUser.setLocalUser(user); return true; } /** * 检查用户是否为管理员 * * @param user 用户 */ private boolean verifyAdmin(UserDO user) { return groupService.checkIsRootByUserId(user.getId()); } private String verifyHeader(HttpServletRequest request) { // 处理头部header,带有access_token的可以访问 String authorization = request.getHeader(AUTHORIZATION_HEADER); if (authorization == null || Strings.isBlank(authorization)) { throw new AuthorizationException(10012); } String[] splits = authorization.split(" "); final int tokenSplitLen = 2; if (splits.length != tokenSplitLen) { throw new AuthorizationException(10013); } // Bearer 字段 String scheme = splits[0]; // token 字段 String tokenStr = splits[1]; if (!Pattern.matches(BEARER_PATTERN, scheme)) { throw new AuthorizationException(10013); } return tokenStr; } }