SpringBoot中验证用户是否登陆有效的几种方法

本文介绍了SpringBoot中验证用户是否登录的有效方法,包括使用拦截器检查session中的loginUser或Token,通过切面进行参数校验,以及利用token进行参数验证。针对不同场景,如后台管理、分布式系统,提供了相应的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

验证用户是否登陆有效的几种方法

最近在阅读几个开源项目的代码,总结一下各种风格的登陆校验

方案一.使用拦截器校验session中是否包含loginUser或Token等信息

结合代码说明:

@Component
public class AdminLoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        String uri = request.getRequestURI();
        if (uri.startsWith("/admin") && null == request.getSession().getAttribute("loginUser")) {
            request.getSession().setAttribute("errorMsg", "请重新登陆");
            response.sendRedirect(request.getContextPath() + "/admin/login");
            return false;
        } else {
            request.getSession().removeAttribute("errorMsg");
            return true;
        }
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

这是一个后台管理用的登陆校验器.

  • 大前提:人为的规范URL格式,后台管理操作URL以"/admin"开头

  • 首先从request中获取到URI链接,然后判断是否以admin开头

  • 然后判断session中的User是否为空 若为空 写入错误信息errormsg到session中,并重定向到登陆界面

  • 记得返回false

  • 若成功,则清除session其中的errorMsg并返回true

方案二 采用切面方式进行参数校验

这段代码出自慕课网廖师兄的SpringBoot的微信点餐系统,这里的情景时实现后台卖家端的是否登陆的校验

先看看代码:

@Aspect
@Component
@Slf4j
public class SellerAuthorizeAspect {
	//自动注入redisTemplate操作redis
    @Autowired
    private StringRedisTemplate redisTemplate;
	//定义一个切面,注意这里将卖家端中用户操作这块的排除了,因为这里包含用户登陆登出,不需要校验.
    @Pointcut("execution(public * com.imooc.controller.Seller*.*(..))" +
    "&& !execution(public * com.imooc.controller.SellerUserController.*(..))")
    public void verify() {}
	
    
    @Before("verify()")
    public void doVerify() {
        //获取request
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
		
        //查询cookie,使用封装好的工具类
        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
        if (cookie == null) {
            //若为空说明没登陆
            log.warn("【登录校验】Cookie中查不到token");
            throw new SellerAuthorizeException();
        }

        //去redis里查询
        String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue()));
        if (StringUtils.isEmpty(tokenValue)) {
            log.warn("【登录校验】Redis中查不到token");
            throw new SellerAuthorizeException();
        }
    }
}

其中,cookie的工具包代码:

package com.imooc.utils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

public class CookieUtil {

    /**
     * 设置
     * @param response
     * @param name
     * @param value
     * @param maxAge
     */
    public static void set(HttpServletResponse response,
                           String name,
                           String value,
                           int maxAge) {
        Cookie cookie = new Cookie(name, value);
        cookie.setPath("/");
        cookie.setMaxAge(maxAge);
        response.addCookie(cookie);
    }

    /**
     * 获取cookie
     * @param request
     * @param name
     * @return
     */
    public static Cookie get(HttpServletRequest request,
                           String name) {
        Map<String, Cookie> cookieMap = readCookieMap(request);
        if (cookieMap.containsKey(name)) {
            return cookieMap.get(name);
        }else {
            return null;
        }
    }

    /**
     * 将cookie封装成Map
     * @param request
     * @return
     */
    private static Map<String, Cookie> readCookieMap(HttpServletRequest request) {
        Map<String, Cookie> cookieMap = new HashMap<>();
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie: cookies) {
                cookieMap.put(cookie.getName(), cookie);
            }
        }
        return cookieMap;
    }
}

这种方式,适用于分布式的登陆校验

方案三.token进行参数校验

这一种方案相对复杂,一步步来吧

首先定义一个注解类

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TokenToUser {

    /**
     * 当前用户在request中的名字
     *
     * @return
     */
    String value() default "user";
}

然后自定义一个参数解析

public class TokenToUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Resource
    private AdminUserService adminUserService;

    public TokenToUserMethodArgumentResolver() {
    }
	 @Override
    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.hasParameterAnnotation(TokenToUser.class)) {
            return true;
        }
        return false;
    }
	 @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        if (parameter.getParameterAnnotation(TokenToUser.class) instanceof TokenToUser) {
            AdminUser user = null;
            //从Request头中获取token
            String token = webRequest.getHeader("token");
            //然后使用token去后台数据库中校验.
            if (null != token && !"".equals(token) && token.length() == 32) {
                user = adminUserService.getAdminUserByToken(token);
            }
            //返回结果
            return user;
        }
       //结果设置为空
        return null;
    }

    public static byte[] getRequestPostBytes(HttpServletRequest request)
            throws IOException {
        int contentLength = request.getContentLength();
        if (contentLength < 0) {
            return null;
        }
        byte buffer[] = new byte[contentLength];
        for (int i = 0; i < contentLength; ) {
            int readlen = request.getInputStream().read(buffer, i,
                    contentLength - i);
            if (readlen == -1) {
                break;
            }
            i += readlen;
        }
        return buffer;
    }

}

控制器中使用方法如下:

    /**
     * 保存
     */
    @RequestMapping("/save")
    public Result save(@RequestBody AdminUser user,@TokenToUser AdminUser loginUser) {
        //此处校验参数解析器解析出来的user是否为空,空则说明登陆校验失败.
        if (loginUser==null){
            return ResultGenerator.genErrorResult(Constants.RESULT_CODE_NOT_LOGIN, "未登录!");
        }
        if (StringUtils.isEmpty(user.getUserName()) || StringUtils.isEmpty(user.getPassword())) {
            return ResultGenerator.genErrorResult(Constants.RESULT_CODE_PARAM_ERROR, "参数异常!");
        }
        AdminUser tempUser = adminUserService.selectByUserName(user.getUserName());
        if (tempUser != null) {
            return ResultGenerator.genErrorResult(Constants.RESULT_CODE_PARAM_ERROR, "用户已存在勿重复添加!");
        }
        if ("admin".endsWith(user.getUserName().trim())) {
            return ResultGenerator.genErrorResult(Constants.RESULT_CODE_PARAM_ERROR, "不能添加admin用户!");
        }
        if (adminUserService.save(user) > 0) {
            return ResultGenerator.genSuccessResult();
        } else {
            return ResultGenerator.genFailResult("添加失败");
        }
    }

最后,如果是SpringBoot的话记得在配置类那里注册一下:

@SpringBootApplication
public class MyBootApplication extends WebMvcConfigurerAdapter{
    public static void main(String[] args) {
        SpringApplication.run(MyBootApplication.class, args);
    }
    
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        super.addArgumentResolvers(argumentResolvers);
        argumentResolvers.add(new TokenToUserMethodArgumentResolver());
    }
}

其实,这种方法也可以改进一下,从cookie中获取token值,然后在redis中校验是否有效,以减轻mysql的压力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值