登录页面在Spring Security的已认证页面上不断重新加载。

huangapple go评论54阅读模式
英文:

The login page keeps reloading on the authenticated page in Spring Security

问题

以下是您提供的内容的翻译:

我正在将Spring Security添加到我的Spring Boot Web项目中。当访问允许页面和受限制页面时,一切正常。但在需要身份验证的页面上,提交登录页面后一直在重新加载。

我怀疑在进行身份验证时出现了问题。我阅读了日志文件,但没有帮助。failureUrl("/login?error=true")没有引发任何异常。

我的代码有什么问题吗?

以下是pom.xml文件:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>  
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>

这是安全配置文件:

@Configuration
@EnableWebSecurity
public class WebSecurity {
    @Autowired
    UserDetailsService userDetailsService;

    @Autowired 
    BCryptPasswordEncoder passwordEncoder;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeHttpRequests((authorize) ->
                        authorize.requestMatchers("/register/**").permitAll()
                                .requestMatchers("/index").permitAll()
                                .requestMatchers("/brand","/shop").hasRole("ADMIN")
                ).formLogin(
                        form -> form
                                .loginPage("/login")
                                .defaultSuccessUrl("/index")
                                .failureUrl("/login?error=true")
                                .permitAll()
                ).logout(
                        logout -> logout
                                .logoutRequestMatcher(new AntPathRequestMatcher("/checkout"))
                                .permitAll()
                );
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/image/**", "/js/**","/css/**");
    }
}

用户类:

public class Users {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;

private String user_name = "anonymous";
private String password;
private Long phone = 12345L;
private String gender = "male";
private String email;
public String main_image = "1.jpeg";
private Date created_date;

private String main_address;
private boolean enabled;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(
        name = "users_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
        )
private List<Role> roles = new ArrayList<>();
}

角色类:

@Entity
@Table(name = "role")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int role_id;
    private String name;

    @ManyToMany(mappedBy="roles")
    private List<Users> users;
}

UserDetailServiceImpl:

public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UsersRepository UsersRepository;

    @Override
    public UserDetails loadUserByUsername(String username) 
            throws UsernameNotFoundException {
        Users user = UsersRepository.getUserByUsername(username);

        if (user is null) {
            throw new UsernameNotFoundException("找不到用户");
        }
        else {
            return new org.springframework.security.core.userdetails.User(user.getUser_name(),
                    user.getPassword(),
                    mapRolesToAuthorities(user.getRoles()));
        }       
    }

    private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles) {
        Collection<? extends GrantedAuthority> mapRoles = roles.stream()
                .map(role -> new SimpleGrantedAuthority(role.getName()))
                .collect(Collectors.toList());
        return mapRoles;
    }
}

日志文件:

Securing POST /shop
2023-03-31T19:38:50.289+07:00 DEBUG 12560 --- [nio-8080-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter  : 设置SecurityContextHolder为匿名SecurityContext
2023-03-31T19:38:50.294+07:00 DEBUG 12560 --- [nio-8080-exec-5] o.s.s.w.s.HttpSessionRequestCache        : 已将请求http://localhost:8080/shop?continue保存到会话中
2023-03-31T19:38:50.298+07:00 DEBUG 12560 --- [nio-8080-exec-5] o.s.s.web.DefaultRedirectStrategy : 重定向到http://localhost:8080/login
2023-03-31T19:38:50.459+07:00 DEBUG 12560 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy        : Securing GET /login
2023-03-31T19:38:50.608+07:00 DEBUG 12560 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy        : Secured GET /login
2023-03-31T19:38:51.094+07:00 DEBUG 12560 --- [nio-8080-exec-6] o.s.s.w.a.AnonymousAuthenticationFilter  : 设置SecurityContextHolder为匿名SecurityContext
英文:

I'm adding spring security to my spring boot web project. It's okay when go to allow page, retristed page. But in needed authentication page, after submit the login page keeps reloading.

I suspect something is wrong when doing the authenticate. I read the log file but no help. The failureUrl(&quot;/login?error=true&quot;) does not raise anything.

What is wrong with my code?

Here the pom

&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-actuator&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
&lt;scope&gt;runtime&lt;/scope&gt;
&lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.mysql&lt;/groupId&gt;
&lt;artifactId&gt;mysql-connector-j&lt;/artifactId&gt;
&lt;scope&gt;runtime&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;
&lt;/dependency&gt;  
&lt;dependency&gt;
&lt;groupId&gt;org.thymeleaf.extras&lt;/groupId&gt;
&lt;artifactId&gt;thymeleaf-extras-springsecurity6&lt;/artifactId&gt;
&lt;/dependency&gt;

Here is the security config file

@Configuration
@EnableWebSecurity
public class WebSecurity {
@Autowired
UserDetailsService userDetailsService;
@Autowired 
BCryptPasswordEncoder passwordEncoder;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests((authorize) -&gt;
authorize.requestMatchers(&quot;/register/**&quot;).permitAll()
.requestMatchers(&quot;/index&quot;).permitAll()
.requestMatchers(&quot;/brand&quot;,&quot;/shop&quot;).hasRole(&quot;ADMIN&quot;)
).formLogin(
form -&gt; form
.loginPage(&quot;/login&quot;)
// .loginProcessingUrl(&quot;/login&quot;)
.defaultSuccessUrl(&quot;/index&quot;)
.failureUrl(&quot;/login?error=true&quot;)
.permitAll()
).logout(
logout -&gt; logout
.logoutRequestMatcher(new AntPathRequestMatcher(&quot;/checkout&quot;))
.permitAll()
);
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -&gt; web.ignoring().requestMatchers(&quot;/image/**&quot;, &quot;/js/**&quot;,&quot;/css/**&quot;);
}

The users class

public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
private String user_name =&quot;anonymous&quot;;
private String password;
private Long phone = 12345L;
private String gender = &quot;male&quot;;
private String email;
public String main_image = &quot;1.jpeg&quot;;
private Date created_date;
private String main_address;
private boolean enabled;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(
name = &quot;users_roles&quot;,
joinColumns = @JoinColumn(name = &quot;user_id&quot;),
inverseJoinColumns = @JoinColumn(name = &quot;role_id&quot;)
)
private List&lt;Role&gt; roles = new ArrayList&lt;&gt;();}

The role class

@Entity
@Table(name = &quot;role&quot;)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int role_id;
private String name;
@ManyToMany(mappedBy=&quot;roles&quot;)
private List&lt;Users&gt; users;
}

Here is the UserDetailServiceImpl

public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UsersRepository UsersRepository;
@Override
public UserDetails loadUserByUsername(String username) 
throws UsernameNotFoundException {
Users user = UsersRepository.getUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(&quot;Could not find user&quot;);
}
else{
return new org.springframework.security.core.userdetails.User(user.getUser_name(),
user.getPassword(),
mapRolesToAuthorities(user.getRoles()));
}		
}
private Collection &lt; ? extends GrantedAuthority&gt; mapRolesToAuthorities(Collection &lt;Role&gt; roles) {
Collection &lt; ? extends GrantedAuthority&gt; mapRoles = roles.stream()
.map(role -&gt; new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
return mapRoles;
}}

Here is the log file

Securing POST /shop2023-03-31T19:38:50.289+07:00 DEBUG 12560 --- [nio-8080-exec-5]o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymousSecurityContext
2023-03-31T19:38:50.294+07:00 DEBUG 12560 --- [nio-8080-exec-5] o.s.s.w.s.HttpSessionRequestCache        : Saved request http://localhost:8080/shop?continue to session2023-03-31T19:38:50.298+07:00 DEBUG 12560 --- [nio-8080-exec-5] o.s.s.web.DefaultRedirectStrategy : Redirecting tohttp://localhost:8080/login 
2023-03-31T19:38:50.459+07:00 DEBUG 12560 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy        : Securing GET /login
2023-03-31T19:38:50.608+07:00 DEBUG 12560 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy        : Secured GET /login
2023-03-31T19:38:51.094+07:00 DEBUG 12560 --- [nio-8080-exec-6] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext

答案1

得分: 0

首先,删除登录的映射方法,因为Spring Security将处理它,我们不需要这样做。

其次,在Thymeleaf登录页面中添加 action=loginth:post

<form action="login" th:method="post">

第三,为输入框添加 name=usernamename=password

<input id="username" type="text" placeholder="用户名" name="username">
<input id="password" type="password" placeholder="密码" name="password">

以下是适用于我的 SecurityFilterChain:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .authorizeHttpRequests((authorize) ->
                    authorize.requestMatchers("/index","/error").permitAll()
                             .requestMatchers("/shop").hasAnyAuthority("ADMIN")
                            .anyRequest().authenticated()
            ).formLogin(
                    form -> form
                            .loginPage("/login")
                            .defaultSuccessUrl("/index")
                            .usernameParameter("username")
                            .passwordParameter("password")
                            .permitAll()
            ).logout(
                    logout -> logout
                            .logoutRequestMatcher(new AntPathRequestMatcher("/checkout"))
                            .permitAll()
            );
    return http.build();
}
英文:

First, delete the Login post mapping method because spring security will handle that, no need for us to do this.

Second, add action=login and th:post to thymelef login page:

&lt;form action=&quot;login&quot; th:method=&quot;post&quot;&gt;

Third, add name=username and name=password for the input:

&lt;input id=&quot;username&quot; type=&quot;text&quot; placeholder=&quot;Username&quot; name=&quot;username&quot;&gt;
&lt;input id=&quot;password&quot; type=&quot;password&quot; placeholder=&quot;Password&quot; name=&quot;password&quot;&gt; 

Here is the SecurityFilterChain that works for me:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests((authorize) -&gt;
authorize.requestMatchers(&quot;/index&quot;,&quot;/error&quot;).permitAll()
.requestMatchers(&quot;/shop&quot;).hasAnyAuthority(&quot;ADMIN&quot;)
.anyRequest().authenticated()
).formLogin(
form -&gt; form
.loginPage(&quot;/login&quot;)
.defaultSuccessUrl(&quot;/index&quot;)
.usernameParameter(&quot;username&quot;)
.passwordParameter(&quot;password&quot;)
.permitAll()
).logout(
logout -&gt; logout
.logoutRequestMatcher(new AntPathRequestMatcher(&quot;/checkout&quot;))
.permitAll()
);
return http.build();
}

huangapple
  • 本文由 发表于 2023年3月31日 21:12:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75898956.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定