若依单体工程,双token,主逻辑不动,放行全部自定义拦截接口,再单独拦截自定义url,登录、获取登录用户信息 ruoyi-framework\src\main\java\com\ruoyi\framework\interceptor\other下 CustomConfig
package com.ruoyi.framework.interceptor.other;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CustomConfig {
@Bean
public FilterRegistrationBean<CustomTokenFilter> newTokenFilter() {
FilterRegistrationBean<CustomTokenFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CustomTokenFilter());
registrationBean.addUrlPatterns("/api/r/**"); // 只对特定路径生效
registrationBean.setOrder(1); // 设置过滤器的顺序,数字越小优先级越高
return registrationBean;
}
}
ruoyi-framework\src\main\java\com\ruoyi\framework\interceptor\other下 CustomTokenFilter
package com.ruoyi.framework.interceptor.other;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.other.LoginUserContext;
import com.ruoyi.common.core.other.TUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.ServletUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 确保此过滤器具有高优先级
public class CustomTokenFilter extends OncePerRequestFilter {
@Autowired
private RedisCache redisCache;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String url = request.getRequestURI();
// 根据URL处理不同的Token逻辑
if (url.startsWith("/api/r/")) {
// 处理特定URL的Token逻辑
String token = request.getHeader("Authorization");
if (token == null || !isValid(token)) {
String msg = com.ruoyi.common.utils.StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.UNAUTHORIZED, msg)));
return;
}
}
// 执行下一个过滤器(包括原有的Token逻辑)
filterChain.doFilter(request, response);
}
private boolean isValid(String token) {
System.out.println(token);
System.out.println(546);
token = token.replaceAll("[^\\w\\s]", "");
if(StringUtils.isBlank(token)){
return false; // 返回验证结果
}
// tokenService.verifyToken(token);
String captcha = redisCache.getCacheObject(CacheConstants.CUSTOM_KEY+token);
if (captcha == null)
{
return false;
}
TUser user = JSON.parseObject(captcha, TUser.class);;
LoginUserContext.setLoginUser(user);
return true; // 返回验证结果
}
}
ruoyi-framework\src\main\java\com\ruoyi\framework\config 下
SecurityConfig
filterChain方法 加入 放行
例如:
.antMatchers("/swagger-ui.html",
"/swagger-resources/**",
"/webjars/**",
"/*/api-docs",
"/druid/**",
"/api/s/user/login", "/api/r/**").permitAll()
说明:首先放行 自定义生成token,其次放行自定义拦截前缀
test login controller
package com.ruoyi.web.controller.api;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.ticket.domain.TUser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 小程序用户
*/
@RestController
@RequestMapping("/api/s/user/")
public class ApiUserController {
// 令牌秘钥
@Value("${token.secret}")
private String secret;
// 令牌有效期(默认30分钟)
@Value("${token.expireTime}")
private int expireTime;
@Autowired
private RedisCache redisCache;
@PostMapping("/login")
public String Login(){
TUser user = new TUser();
user.setDefaultValues(); // 设置默认值
// 现在 user 对象已经设置了默认值,你可以继续操作
System.out.println(user);
String tokenc = IdUtils.fastUUID();
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_S_USER_KEY, tokenc);
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
token = token.replaceAll("[^\\w\\s]", "");
redisCache.setCacheObject(CacheConstants.CUSTOM_KEY+token,JSONObject.from(user).toString(), Constants.S_EXPIRE_TIME, TimeUnit.MINUTES);
return token;
}
}
说明:123456位置可以随意填写,建议放入用户信息
验证
package com.ruoyi.web.controller.api;
import com.ruoyi.common.core.controller.CustomBaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户测试方法
*
* @author ruoyi
*/
@RestController
@RequestMapping("/api/r/")
public class Test2Controller extends CustomBaseController
{
@GetMapping("get")
public AjaxResult get()
{
return AjaxResult.success(getLoginUser());
}
}
ruoyi-common\src\main\java\com\ruoyi\common\core\controller 下
自定义 CustomBaseController
package com.ruoyi.common.core.controller;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.other.LoginUserContext;
import com.ruoyi.common.core.other.TUser;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sql.SqlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
/**
* web层通用数据处理
*
* @author autsch
*/
public class CustomBaseController
{
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder)
{
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text)
{
setValue(DateUtils.parseDate(text));
}
});
}
/**
* 设置请求分页数据
*/
protected void startPage()
{
PageUtils.startPage();
}
/**
* 设置请求排序数据
*/
protected void startOrderBy()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
PageHelper.orderBy(orderBy);
}
}
/**
* 清理分页的线程变量
*/
protected void clearPage()
{
PageUtils.clearPage();
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected TableDataInfo getDataTable(List<?> list)
{
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.SUCCESS);
rspData.setMsg("查询成功");
rspData.setRows(list);
rspData.setTotal(new PageInfo(list).getTotal());
return rspData;
}
/**
* 返回成功
*/
public AjaxResult success()
{
return AjaxResult.success();
}
/**
* 返回失败消息
*/
public AjaxResult error()
{
return AjaxResult.error();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message)
{
return AjaxResult.success(message);
}
/**
* 返回成功消息
*/
public AjaxResult success(Object data)
{
return AjaxResult.success(data);
}
/**
* 返回失败消息
*/
public AjaxResult error(String message)
{
return AjaxResult.error(message);
}
/**
* 返回警告消息
*/
public AjaxResult warn(String message)
{
return AjaxResult.warn(message);
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(int rows)
{
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result)
{
return result ? success() : error();
}
/**
* 页面跳转
*/
public String redirect(String url)
{
return StringUtils.format("redirect:{}", url);
}
/**
* 获取用户缓存信息
*/
public TUser getLoginUser()
{
return LoginUserContext.getLoginUser();
}
/**
* 获取登录用户id
*/
public Long getUserId()
{
return getLoginUser().getId();
}
/**
* 获取登录用户名
*/
public String getNickName()
{
return getLoginUser().getNickName();
}
}
ruoyi-common\src\main\java\com\ruoyi\common\core\other 下
LoginUserContext
package com.ruoyi.common.core.other;
public class LoginUserContext {
private static final ThreadLocal<TUser> userHolder = new ThreadLocal<>();
public static void setLoginUser(TUser loginUser) {
userHolder.set(loginUser);
}
public static TUser getLoginUser() {
return userHolder.get();
}
public static void clear() {
userHolder.remove();
}
}
ruoyi-common\src\main\java\com\ruoyi\common\core\other 下
TUser
package com.ruoyi.common.core.other;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 小程序用户对象 t_user
*
* @author autsch
* @date 2024-08-09
*/
public class TUser extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** ID */
@TableId(value = "id",type = IdType.AUTO)
private Long id;
/** openId */
@Excel(name = "openId")
private String openId;
/** 头像 */
@Excel(name = "头像")
private String photo;
/** 昵称 */
@Excel(name = "昵称")
private String nickName;
/** 手机号 */
@Excel(name = "手机号")
private String phone;
/** 0存在1删除 */
@Excel(name = "0存在1删除")
private String isDel;
/** 0正常 1禁用,禁用后进入平台直接弹窗 预留 */
@Excel(name = "0正常 1禁用,禁用后进入平台直接弹窗 预留")
private String isForbidden;
/** 0已认证 1未认证 */
@Excel(name = "0已认证 1未认证")
private String isReal;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setOpenId(String openId)
{
this.openId = openId;
}
public String getOpenId()
{
return openId;
}
public void setPhoto(String photo)
{
this.photo = photo;
}
public String getPhoto()
{
return photo;
}
public void setNickName(String nickName)
{
this.nickName = nickName;
}
public String getNickName()
{
return nickName;
}
public void setPhone(String phone)
{
this.phone = phone;
}
public String getPhone()
{
return phone;
}
public void setIsDel(String isDel)
{
this.isDel = isDel;
}
public String getIsDel()
{
return isDel;
}
public void setIsForbidden(String isForbidden)
{
this.isForbidden = isForbidden;
}
public String getIsForbidden()
{
return isForbidden;
}
public void setIsReal(String isReal)
{
this.isReal = isReal;
}
public String getIsReal()
{
return isReal;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("openId", getOpenId())
.append("photo", getPhoto())
.append("nickName", getNickName())
.append("phone", getPhone())
.append("isDel", getIsDel())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.append("isForbidden", getIsForbidden())
.append("isReal", getIsReal())
.toString();
}
public void setDefaultValues() {
this.openId = "defaultOpenId";
this.photo = "defaultPhotoUrl";
this.nickName = "匿名用户";
this.phone = "00000000000";
this.isDel = "0";
this.isForbidden = "0";
this.isReal = "1";
}
}
ruoyi-common\src\main\java\com\ruoyi\common\constant下
CacheConstants
package com.ruoyi.common.constant;
/**
* 缓存的key 常量
*
* @author ruoyi
*/
public class CacheConstants
{
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";
/**
* 防重提交 redis key
*/
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
/**
* 限流 redis key
*/
public static final String RATE_LIMIT_KEY = "rate_limit:";
/**
* 登录账户密码错误次数 redis key
*/
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
/**
* 小程序用户 cache key
*/
public static final String CUSTOM_KEY = "custom_user:";
}