Spring Security hasAuthority功能异常,登录后返回403错误排查
问题原因分析
- 权限匹配顺序逻辑错误:Spring Security 会按
antMatchers的编写顺序从上到下匹配路径,命中第一条符合的规则后就不再校验后续规则。你同时给/dashboard分别配置了ADMIN和USER的角色要求,USER访问时会先命中第一条需要ADMIN权限的规则,直接被拦截返回403。 - 角色校验规则不统一:
hasRole()方法会自动给传入的角色名拼接ROLE_前缀后再做权限匹配,而你后续的SUPER_ADMIN用了hasAuthority()方法(该方法不会拼接前缀,直接做完全匹配),同时身份认证成功的Handler里判断的是无前缀的角色名,三者规则不统一导致权限校验失败。 - 路径权限配置冗余:按照需求USER角色登录后只会跳转
/pos,不需要访问/dashboard,你额外给USER配置/dashboard权限反而造成了规则冲突。 - 超级管理员权限规则异常:你把
/**需要SUPER_ADMIN权限的规则放在了所有路径规则最后,前面已经限定了大量路径只有ADMIN/USER可以访问,导致SUPER_ADMIN也无法访问这些路径。
修复方案
- 统一权限校验规则:全部改用
hasAuthority()做权限匹配,避免ROLE_前缀的问题 - 调整路径匹配顺序:细粒度路径规则放在前面,粗粒度规则放在后面,同时给多角色可访问的路径配置多权限校验
- 移除冗余的USER角色
/dashboard权限配置 - 调整超级管理员的权限规则,支持其访问所有路径
- 优化登录成功Handler的角色判断逻辑,避免异常角色跳转错误
修复后代码
安全配置类修改
@Override protected void configure(HttpSecurity http) throws Exception { String loginPage = "/login"; String logoutPage = "/logout"; http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) .and() .authorizeRequests() .antMatchers(loginPage).permitAll() // ADMIN和SUPER_ADMIN都可访问的管理后台路径 .antMatchers("/dashboard", "/boxes/**", "/manufacturers/**", "/brands/**", "/stocks/**", "/suppliers/**", "/saleinvoices/**", "/purchaseinvoices/**", "/purchases/**", "/sales/**", "/returns/**", "/users/**").hasAnyAuthority("ADMIN","SUPER_ADMIN") // USER可访问的路径 .antMatchers("/stocks/**", "/pos").hasAnyAuthority("USER","SUPER_ADMIN") // 剩余所有路径只有SUPER_ADMIN可访问 .antMatchers("/**").hasAuthority("SUPER_ADMIN") .anyRequest().authenticated() .and() .csrf().disable() .formLogin() .loginPage(loginPage).permitAll() .loginPage("/") .failureUrl("/login?error=true") .successHandler(authenticationSuccessHandler) .usernameParameter("username") .passwordParameter("password") .and() .logout() .logoutRequestMatcher(new AntPathRequestMatcher(logoutPage)) .logoutSuccessUrl(loginPage) .and() .exceptionHandling(); }
登录成功Handler修改
@Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { Set<String> roles = AuthorityUtils.authorityListToSet(authentication.getAuthorities()); if (roles.contains("USER")) { httpServletResponse.sendRedirect("/pos"); } else if (roles.contains("ADMIN") || roles.contains("SUPER_ADMIN")) { httpServletResponse.sendRedirect("/dashboard"); } else { // 无匹配角色跳转登录页 httpServletResponse.sendRedirect("/login?error=role"); } }
注:请确认你的
CustomUserDetailsService返回的权限字符串和代码中判断的"ADMIN"、"USER"、"SUPER_ADMIN"完全一致,不一致的话对应修改即可。
内容的提问来源于stack exchange,提问作者Sadman Sobhan
相关产品推荐
相关产品推荐

