此文章为了解决匿名可以访问图片问题,有的文章是重构了el-img组件,使用blob重新进行加载。该文章是换个思路,在图片访问地址后面追加token参数,后端进行拦截,判断token是否有效,无效则拦截。反之通过。同时会校验是否同一台电脑、同一浏览器、同一操作系统、同一登录地点
前端:
image-preview组件:
<template> <el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" append-to-body="true" > <template #error> <div class="image-slot"> <el-icon><picture-filled /></el-icon> </div> </template> </el-image></template><script setup>import { isExternal } from "@/utils/validate";import { getToken } from "@/utils/auth";import {watch} from "vue";const tokenInfo = ref(getToken())const props = defineProps({ src: { type: String, required: true }, srcViewerList: { type: Array }, width: { type: [Number, String], default: "" }, height: { type: [Number, String], default: "" }});const realSrc = computed(() => { let real_src = props.src.split(",")[0]; if (isExternal(real_src)) { return real_src; } return import.meta.env.VITE_APP_BASE_API + real_src + '?token=' + tokenInfo.value;});const realSrcList = ref([]);watch(() => { props.srcViewerList.forEach(item => { realSrcList.value.push(item + '?token=' + tokenInfo.value) });})// const realSrcList = computed(() => {// let real_src_list = props.src.split(",");// let srcList = [];// real_src_list.forEach(item => {// if (isExternal(item)) {// return srcList.push(item);// }// return srcList.push(import.meta.env.VITE_APP_BASE_API + item + '?token=' + tokenInfo.value);// });// return srcList;// });const realWidth = computed(() => typeof props.width == "string" ? props.width : `${props.width}px`);const realHeight = computed(() => typeof props.height == "string" ? props.height : `${props.height}px`);</script><style lang="scss" scoped>.el-image { border-radius: 5px; background-color: #ebeef5; box-shadow: 0 0 5px 1px #ccc; :deep(.el-image__inner) { transition: all 0.3s; cursor: pointer; &:hover { transform: scale(1.2); } } :deep(.image-slot) { display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; color: #909399; font-size: 30px; }}</style>
后端拦截器:
ProfileInterceptorConfig.java
package com.fuel.framework.config;import com.fuel.framework.interceptor.ProfileInterceptor;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * 通用配置 * * @author hhxx */@Configurationpublic class ProfileInterceptorConfig implements WebMvcConfigurer{ @Autowired private ProfileInterceptor profileInterceptor; /** * 自定义拦截规则 */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(profileInterceptor) .addPathPatterns("/profile/**"); }}
ProfileInterceptor.java
package com.fuel.framework.interceptor;import com.alibaba.fastjson2.JSON;import com.fuel.common.constant.HttpStatus;import com.fuel.common.core.domain.AjaxResult;import com.fuel.common.core.domain.model.LoginUser;import com.fuel.common.utils.ServletUtils;import com.fuel.common.utils.StringUtils;import com.fuel.common.utils.ip.AddressUtils;import com.fuel.common.utils.ip.IpUtils;import com.fuel.common.utils.spring.SpringUtils;import com.fuel.framework.security.handle.AuthenticationEntryPointImpl;import com.fuel.framework.web.service.TokenService;import eu.bitwalker.useragentutils.UserAgent;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Map;@Componentpublic class ProfileInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取token String token = request.getParameter("token"); // 获取用户代理 UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); // 获取ip String ipaddr = IpUtils.getIpAddr(ServletUtils.getRequest()); // 获取登录地点 String loginLocation = AddressUtils.getRealAddressByIP(ipaddr); // 获取浏览器 String browser = userAgent.getBrowser().getName(); // 获取操作系统 String os = userAgent.getOperatingSystem().getName(); TokenService bean = SpringUtils.getBean(TokenService.class); AuthenticationEntryPointImpl authenticationEntryPointImpl = SpringUtils.getBean(AuthenticationEntryPointImpl.class); // 校验token是否有效 Map<String, Object> stringObjectMap = bean.verifyToken(token); boolean bl = false; if (stringObjectMap.size() > 0) { // 获取登录信息 LoginUser user = (LoginUser) stringObjectMap.get("user"); // 判断是否同一台电脑、同一浏览器、同一操作系统、同一登录地点 if (user != null && ipaddr.equals(user.getIpaddr()) && loginLocation.equals(user.getLoginLocation()) && browser.equals(user.getBrowser()) && os.equals(user.getOs())) { bl = true; } } if(!bl){ // 校验不通过时返回错误信息--复用Spring Security框架的信息 authenticationEntryPointImpl.commence(request, response, null); } return bl; }}
TokenService.java
package com.fuel.framework.web.service;import java.util.HashMap;import java.util.Map;import java.util.concurrent.TimeUnit;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.alibaba.fastjson2.JSONArray;import com.alibaba.fastjson2.JSONObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;import com.auth0.jwt.exceptions.JWTVerificationException;import com.auth0.jwt.exceptions.TokenExpiredException;import com.fuel.common.constant.Constants;import com.fuel.common.core.domain.AjaxResult;import com.fuel.common.core.domain.model.LoginUser;import com.fuel.common.core.redis.RedisCache;import com.fuel.common.utils.MessageUtils;import com.fuel.common.utils.ServletUtils;import com.fuel.common.utils.StringUtils;import com.fuel.common.utils.http.HttpUtils;import com.fuel.common.utils.ip.AddressUtils;import com.fuel.common.utils.ip.IpUtils;import com.fuel.common.utils.uuid.IdUtils;import eu.bitwalker.useragentutils.UserAgent;import io.jsonwebtoken.Claims;import io.jsonwebtoken.ExpiredJwtException;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;/** * token验证处理 * * @author hhxx */@Componentpublic class TokenService{ // 令牌自定义标识 @Value("${token.header}") private String header; // 令牌秘钥 @Value("${token.secret}") private String secret; // 令牌有效期(默认30分钟) @Value("${token.expireTime}") private int expireTime; protected static final long MILLIS_SECOND = 1000; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L; @Autowired private RedisCache redisCache; /*** * 验证令牌 * @param token * @return */ public Map<String,Object> verifyToken(String token) { Map<String,Object> resultMap = new HashMap<>(); boolean bl = true; try { Claims claims = parseToken(token); // 解析对应的权限以及用户信息 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); String userKey = getTokenKey(uuid); LoginUser user = JSONObject.parseObject(redisCache.getCacheObject(userKey),LoginUser.class); if(user != null) { bl = true; resultMap.put("bl", bl); }else { bl = false; resultMap.put("bl", bl); resultMap.put("msg", "token已过期"); } }catch (ExpiredJwtException eje) { bl = false; resultMap.put("bl", bl); resultMap.put("msg", "token已过期"); } catch(Exception ex) { bl = false; resultMap.put("bl", bl); resultMap.put("msg", "token验证异常"); } return resultMap; } }