为啥spring security hasRole函数不认证任何api

Posted

技术标签:

【中文标题】为啥spring security hasRole函数不认证任何api【英文标题】:why spring security hasRole function does not authenticate any apis为什么spring security hasRole函数不认证任何api 【发布时间】:2020-02-29 11:58:53 【问题描述】:

我在使用spring security hasRole 时遇到了一些麻烦。我在数据库中有 2 个角色保存为 ROLE_ADMINROLE_USER。我想允许一些具有 ADMIN 角色的 API,一些具有 USER 角色的 API。这是我的代码。

安全配置

@Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter 

        @Autowired
        private DataSource dataSource;

        @Value("$spring.queries.users-query")
        private String usersQuery;

        @Value("$spring.queries.roles-query")
        private String rolesQuery;

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception 

            auth
                    .jdbcAuthentication()
                    .dataSource(dataSource)
                    .passwordEncoder(bCryptPasswordEncoder())
                    .usersByUsernameQuery(usersQuery)
                    .authoritiesByUsernameQuery(rolesQuery);
        

        @Override
        protected void configure(HttpSecurity http) 
            System.out.println("configure " );
            try 
                http.csrf().disable().authorizeRequests()
                        .antMatchers("/", "/*.html").permitAll()
                        .antMatchers("/home").permitAll()
                        .antMatchers("/login").permitAll()
                        .antMatchers("/profile/").hasAnyRole("ADMIN","USER")

                        .antMatchers("/admin/*").hasRole("ADMIN")
                        .antMatchers("/insurance/*").hasRole("ADMIN")
                        .antMatchers("/company/*").hasRole("ADMIN")
                        .anyRequest().authenticated();

             catch (Exception e) 
                e.printStackTrace();
            
        

        @Override
        public void configure(WebSecurity web) 
            web.httpFirewall(allowUrlEncodedSlashHttpFirewall())
                    .ignoring()
                    .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/templates/**");

        

        @Bean
        public HttpFirewall allowUrlEncodedSlashHttpFirewall() 
            StrictHttpFirewall firewall = new StrictHttpFirewall();
        /*firewall.setAllowUrlEncodedSlash(true);
        firewall.setAllowSemicolon(true);*/
            firewall.setAllowUrlEncodedDoubleSlash(true);
            return firewall;
        

        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() 
            return new BCryptPasswordEncoder();
        

我在application.properties 中有sql queries

spring.queries.users-query=select username, password, status from insurance.users where username=?
spring.queries.roles-query=select u.username, r.role from insurance.users u inner join insurance.roles r on(u.role_id=r.id) where u.username=?

问题是当我尝试登录时,我收到 403 错误代码。

这里是Controller.class

 @RequestMapping(value = "/login", method = RequestMethod.POST)
        public String login(@RequestParam(value = "email") String email,
                            @RequestParam(value = "password") String password, HttpSession session) 
            Result result = userService.login(email, password);
            session.setAttribute("user", result.getData());

            if(result.getStatus() == 200)
                return  "redirect:/profile";
             else 
                return "redirect:/login?error";
            
        

        @RequestMapping(value = "/profile", method = RequestMethod.GET)
        public String profile(HttpSession httpSession, Model model) 
            if(httpSession.getAttribute("user") != null) 
                UserResponse user = (UserResponse) httpSession.getAttribute("user");
                model.addAttribute("user", user);
                return "profile";
             else 
                return "redirect:/home";
            
        

我试图解决它,但找不到。如果您有任何建议,请告诉。

我按照建议更改了我的配置文件。我添加了自定义登录逻辑,现在当我想去 /admins 或其他 url 时,我 重定向到登录 url 这是我的配置代码

protected void configure(HttpSecurity http) 
        try 
            http.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/home").permitAll()
                    .antMatchers("/admin/**").hasRole("ADMIN")
                    .antMatchers("/insurance/*").hasRole("ADMIN")
                    .antMatchers("/company/*").hasRole("ADMIN")
                    .and()
                    .formLogin()
                    .loginPage("/login.html").permitAll().usernameParameter("username") .passwordParameter("password")
                    .loginProcessingUrl("/login")
                    .defaultSuccessUrl("/profile.html", true);

         catch (Exception e) 
            e.printStackTrace();
        
    

【问题讨论】:

您有自己的登录名,不要。 Spring Security 应该解决这个问题。您有规则,但 Spring Security 永远不会看到登录用户,因为该过程完全绕过 Spring Security。 @M.Deinum,你能再看看我的代码吗。我按照你说的更新了 从您的配置方法中删除try/catch。同样,如果不设置身份验证管理器,它也不会做任何事情。 【参考方案1】:

只需在身份验证例外中添加登录名即可。 试试这个

protected void configure(HttpSecurity http) 
        try 
            http.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/login").permitAll()
                    .antMatchers("/home").permitAll()
                    .antMatchers("/admin/**").hasRole("ADMIN")
                    .antMatchers("/insurance/*").hasRole("ADMIN")
                    .antMatchers("/company/*").hasRole("ADMIN")
                    .and()
                    .formLogin()
                    .loginPage("/login.html").permitAll().usernameParameter("username") .passwordParameter("password")
                    .loginProcessingUrl("/login")
                    .defaultSuccessUrl("/profile.html", true);

         catch (Exception e) 
            e.printStackTrace();
        
    

【讨论】:

您建议使用哪种登录方式?对不起,我没听懂您的意思 我说的是 .antMatchers("/login").permitALL() 基本上您需要删除登录 API 本身的身份验证才能使用它进行身份验证(因为您当时尚未经过身份验证) 我按照你说的删除了登录部分,仍然没有运气。不过谢谢 我要求您将登录部分添加到全部许可中

以上是关于为啥spring security hasRole函数不认证任何api的主要内容,如果未能解决你的问题,请参考以下文章

如何正确使用 Spring Security 中的 hasRole?

如何对 Spring Security @PreAuthorize(hasRole) 进行单元测试?

Spring Security 中的 hasRole() 无法正常工作 [重复]

Spring Security 'Roles' 和 'Privileges' 和 Thymeleaf 'hasRole' 和 'hasAuthority'

如何使用 Spring Security 检查 Java 代码中的“hasRole”?

Spring Security with hibernate:hasRole() 在配置中不起作用