英文:
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("/login?error=true")
does not raise anything.
What is wrong with my code?
Here the pom
<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>
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) ->
authorize.requestMatchers("/register/**").permitAll()
.requestMatchers("/index").permitAll()
.requestMatchers("/brand","/shop").hasRole("ADMIN")
).formLogin(
form -> form
.loginPage("/login")
// .loginProcessingUrl("/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/**");
}
The users class
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<>();}
The role class
@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;
}
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("Could not find user");
}
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;
}}
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=login
和 th:post
:
<form action="login" th:method="post">
第三,为输入框添加 name=username
和 name=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:
<form action="login" th:method="post">
Third, add name=username
and name=password
for the input:
<input id="username" type="text" placeholder="Username" name="username">
<input id="password" type="password" placeholder="Password" name="password">
Here is the SecurityFilterChain that works for me:
@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();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论