[英]Spring security login always lands in an error page with no message
我在 Spring 中為一個小項目使用登錄表單,但我有一個小問題,即每次我使用登錄表單登錄時,都會收到錯誤重定向。
這是我的 SecurityConfiguration.java
package com.ffuentese;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private DataSource dataSource;
@Value("${spring.queries.users-query}")
private String usersQuery;
@Value("${spring.queries.roles-query}")
private String rolesQuery;
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.
jdbcAuthentication()
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(rolesQuery)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration").permitAll()
.antMatchers("/**").hasAuthority("ADMIN").anyRequest()
.authenticated().and().csrf().disable().formLogin()
.loginPage("/login").failureUrl("/login?error=true")
.defaultSuccessUrl("/home")
.usernameParameter("email")
.passwordParameter("password")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and().exceptionHandling()
.accessDeniedPage("/access-denied");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
}
}
我的簽到表:
<form th:action="@{/login}" method="POST" class="form-signin">
<h3 class="form-signin-heading" th:text="Welcome"></h3>
<br/>
<input type="text" id="email" name="email" th:placeholder="Email"
class="form-control" /> <br/>
<input type="password" th:placeholder="Password"
id="password" name="password" class="form-control" /> <br />
<div align="center" th:if="${param.error}">
<p style="font-size: 20; color: #FF1C19;">Email or contraseña errónea, por favor intente nuevamente.</p>
</div>
<button class="btn btn-lg btn-primary btn-block" name="Submit" value="Login" type="Submit" th:text="Login"></button>
</form>
我的 loginController.java
package com.ffuentese;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.ffuentese.User;
@Controller
public class LoginController {
@Autowired
private UserService userService;
@RequestMapping(value={"/", "/login"}, method = RequestMethod.GET)
public ModelAndView login(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("login");
return modelAndView;
}
@RequestMapping(value="/home", method = RequestMethod.GET)
public ModelAndView homeV(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
modelAndView.setViewName("home");
return modelAndView;
}
@RequestMapping(value="/registration", method = RequestMethod.GET)
public ModelAndView registration(){
ModelAndView modelAndView = new ModelAndView();
User user = new User();
modelAndView.addObject("user", user);
modelAndView.setViewName("registration");
return modelAndView;
}
@RequestMapping(value = "/registration", method = RequestMethod.POST)
public ModelAndView createNewUser(@Valid User user, BindingResult bindingResult) {
ModelAndView modelAndView = new ModelAndView();
User userExists = userService.findUserByEmail(user.getEmail());
if (userExists != null) {
bindingResult
.rejectValue("email", "error.user",
"There is already a user registered with the email provided");
}
if (bindingResult.hasErrors()) {
modelAndView.setViewName("registration");
} else {
userService.saveUser(user);
modelAndView.addObject("successMessage", "User has been registered successfully");
modelAndView.addObject("user", new User());
modelAndView.setViewName("registration");
}
return modelAndView;
}
@RequestMapping(value="/admin/home", method = RequestMethod.GET)
public ModelAndView home(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("userName", "Welcome " + user.getName() + " " + user.getLastName() + " (" + user.getEmail() + ")");
modelAndView.addObject("adminMessage","Content Available Only for Users with Admin Role");
modelAndView.setViewName("admin/home");
return modelAndView;
}
}
因此,不是從登錄到 /home,它最終會登陸 /error。 錯誤本身是這樣一行代碼:
{"timestamp":"2018-04-04T21:28:28.944+0000","status":999,"error":"None","message":"無可用消息"}
該表單確實有效,因為如果我從 /error 移動並轉到任何受保護的 URL,它們可以被打開。
編輯:原始代碼來自這個存儲庫,我將它改編成我自己的項目https://github.com/gustavoponce7/SpringSecurityLoginTutorial也在這里解釋
編輯:我認為重要的另一點是,如果我登錄然后再次登錄,表單似乎可以正常工作,使用戶按預期從登錄到 /home。 這很奇怪。
您可以將always-use-default-target
參數添加到成功 URL。
.defaultSuccessUrl("/home",true)
這意味着如果登錄成功,您將始終被發送到/home
。
我認為不良行為是由於某種原因導致錯誤頁面排隊,然后當登錄成功時,您會“返回”該頁面。
這不是理想的解決方案,但如果您不想在登錄后轉到上一頁,那么它可以防止您描述的行為。
也許這是關於那個,沒有帶有Param
錯誤的RequestMapping
。 可能的解決方案
@RequestMapping(value={"/", "/login"}, method = RequestMethod.GET)
public ModelAndView login(@RequestParam(value = "error", required = false)){
ModelAndView modelAndView = new ModelAndView();
if (error != null) {
modelAndView.setViewName("error page");
} else modelAndView.setViewName("login");
return modelAndView;
}
也可能是由於您的項目中沒有以下所有文件夾"/static/**", "/js/**", "/css/**", "/img/**", "/json/**"
,刪除此配置或添加所有文件夾。
我想這個問題得到了回答,我今天遇到了這個錯誤,我遇到了不同的情況。 我認為這會對其他一些新的 Spring 編碼員有所幫助,因為我不得不用谷歌搜索一段時間。
有必要將屬性名稱添加到用戶名或密碼文本字段。 在相應的輸入類型中添加屬性name="username" 和name="password" 后,您必須能夠登錄。
Spring 使用 name 參數進行用戶名和密碼的匹配。 所以它是必須的! 這可能看起來很簡單,但這就是它的工作原理
適合我的情況的答案也是123
分享的答案。
https://www.baeldung.com/spring-security-login 上的以下建議也派上用場:
覆蓋 Spring Security 中大多數默認值的一個原因是隱藏應用程序受 Spring Security 保護的事實,並最大限度地減少潛在攻擊者知道的有關應用程序的信息。
defaultSuccessUrl(String defaultSuccessUrl)指定如果用戶在驗證之前沒有訪問過安全頁面,則在驗證成功后用戶將去往何處。
defaultSuccessUrl(String defaultSuccessUrl, boolean alwaysUse)指定如果用戶在身份驗證之前沒有訪問過安全頁面或 alwaysUse 為真,則用戶在身份驗證成功后將去往何處。
如果您是第一次使用默認身份驗證,則創建一個控制器並處理默認請求(即獲取 '/' )
在我的情況下,還有一些其他請求導致這種情況發生(其中一個是加載 css 資源時的 404)。 修復它們后,此錯誤消失了。
編輯
要正確解決問題,您應該從 spring 安全過濾器中排除/error
頁面。 檢查Spring 安全重定向到狀態碼為 999 的頁面以獲取詳細信息
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.