You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot项目登录失败,凭证验证返回无效提示问题咨询

登录失败问题修复

首先排查当前认证不通过的核心问题,按优先级修改:

  • 修复Policy单例并发异常
    你通过@Autowired注入的Policy默认是单例全局对象,每次请求调用policy.getPredicates().add()都会往同一个对象里累加谓词规则,多次请求后规则会重复混乱,必然导致认证失败。同时多线程场景下不同用户的请求会互相修改Policy参数,也会触发认证错误。
    修改方案:认证时使用局部Policy实例,不要复用全局注入的对象:
@PostMapping("/authenticate")
public RedirectView authenticate(@Valid @ModelAttribute LoginRequest loginRequest, BindingResult bindingResult, Model model, HttpServletRequest request) throws AuthenticationFailedException, TokenGenerationException {
    if (bindingResult.hasErrors()) {
        // 校验用户名密码是否为空,直接返回登录失败
        return new RedirectView("/loginFailed", true);
    }
    try {
        // 新建局部Policy实例,避免多线程并发问题
        Policy localPolicy = new Policy();
        localPolicy.setPolicyId((String) request.getSession().getAttribute("nonce"));
        localPolicy.getPredicates().add(new Predicate("audience", Operation.REVEAL, new Attribute("olympus-service-provider")));
        
        String token = userClient.authenticate(loginRequest.getUsername(), loginRequest.getPassword(), localPolicy, null, "NONE");
        // 认证成功后存储登录态到session
        request.getSession().setAttribute("loginUser", loginRequest.getUsername());
        // 解析token的过期时间存入session,后续校验用
        request.getSession().setAttribute("tokenExpire", parseExpireTimeFromToken(token));
        
        String redirectUrl = (String) request.getSession().getAttribute("redirectUrl");
        String state = (String) request.getSession().getAttribute("state");
        return new RedirectView(redirectUrl + "#state=" + state + "&id_token=" + token + "&token_type=bearer");
    } catch (Exception e) {
        e.printStackTrace();
        if (ExceptionUtils.indexOfThrowable(e, AuthenticationFailedException.class) != -1) {
            return new RedirectView("/loginFailed", true);
        } else {
            throw e;
        }
    } finally {
        // 确认UserClient是请求作用域Bean再保留该逻辑,否则会清空所有用户的会话
        // userClient.clearSession();
    }
}
  • 补充请求参数绑定注解
    给LoginRequest参数加@ModelAttribute注解,确保表单提交的账号密码能正确绑定到对象,避免参数为空导致的认证失败。

需求实现

1. 访问站点先完成身份校验

通过Spring Boot拦截器实现全局登录校验:
首先编写登录拦截器:

@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String uri = request.getRequestURI();
        // 放行登录相关的公开接口
        if (uri.startsWith("/login") || uri.startsWith("/authenticate") || uri.startsWith("/loginPage") || uri.startsWith("/loginFailed")) {
            return true;
        }
        // 校验session中是否存在有效登录态
        Object loginUser = request.getSession().getAttribute("loginUser");
        Long tokenExpire = (Long) request.getSession().getAttribute("tokenExpire");
        if (loginUser == null || System.currentTimeMillis() > tokenExpire) {
            // 未登录/身份过期,跳转到登录页
            response.sendRedirect("/loginPage");
            return false;
        }
        return true;
    }
}

注册拦截器到Spring容器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor).addPathPatterns("/**");
    }
}

2. 身份失效触发登出逻辑

新增登出接口,清理会话状态:

@RequestMapping("/logout")
public RedirectView logout(HttpServletRequest request) {
    // 销毁当前用户的session
    request.getSession().invalidate();
    // 清理用户在Olympus客户端的会话
    userClient.clearSession();
    // 跳转到登录页
    return new RedirectView("/loginPage?logout=success");
}

拦截器已经内置了token过期自动触发登出的逻辑,也可以在前端添加定时器定时校验token有效性,过期主动调用/logout接口完成登出。

内容的提问来源于stack exchange,提问作者user14485278

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 12:36:05