java - Spring Boot安全自定义登录页面到不同的url“/”不起作用
问题描述
我刚刚查看了许多关于自定义登录页面的示例,每个示例都使用相同的“/login”路径。经过这么多挫折后,我终于让登录以使用默认值。
我希望在“/”处呈现登录表单而不是登录。
一旦通过身份验证,我希望它进入“/home”。
我假设 POST 仍然会转到默认的“/登录”?
我在 POST 表单“/”(与 GET 表单的路径相同)和“/login”上都试过了
现在,当我尝试登录时,它不断将我重定向回与表单相同的“/”。
这里还是基本的 API 逻辑:默认登录页面应该在“/”,Form 发布到“/login”,登录后的 Success Url 是“/home”,“/home”和“/mama”是受保护的路由。注销后,它应该重定向到“/”
我无法通过该应用程序,并且不确定是否缺少任何内容,即使密码显然没问题,它仍然显示相同的登录表单,就好像我没有通过一样
以下是 WebConfigurerAdapter 文件管理器中解释的路由:
@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
/*auth.inMemoryAuthentication()
.withUser("appuser").password("1234").roles("HEAD")
.and()
.withUser("Mama").password("Mama").roles("MAMA");*/
}
@Override
/*
* Now we have learnt the basics of Spring Security & Authrization method is completed.
* Lets fix Authentication first!
* Got it to work with hasAuthority & hasAnyAuthority but not with roles, not sure why, but it works atm
*
* */
protected void configure(HttpSecurity http) throws Exception {
//Disabled for development
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/mama").hasAuthority("MAMA")
.antMatchers("/home").hasAnyAuthority("HEAD", "MAMA")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/").permitAll()
.defaultSuccessUrl("/home")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutSuccessUrl("/");
}
@Bean
/*
* Returning no op password encoder for now, as we are not encoding passwords as no registration
* implemented for Prototype. We would need to add the users from a separate service. W
*
* */
public PasswordEncoder getPasswordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
}
//LoginApi:
@RestController
public class LoginApi {
@RequestMapping("/")
public String index(){
return "<form method='POST' action='/login'>" +
"<div>" +
"<input type='text' name='username' placeholder='Username: ' />" +
"</div>" +
"<div>" +
"<input type='password' name='password' placeholder='Password: ' />" +
"</div>" +
"<div>" +
"<input type='submit' name='submit' value='Login' />" +
"</div>" +
"</form>";
}
@RequestMapping("/home")
public String home(){
return "Welcome to Home!";
}
/*
* This method can be deleted in the end
* */
@RequestMapping("/mama")
public String roleTest(){
return "This end point is only for Mama!";
}
}
对于这个测试,我没有使用数据库,但我有一个 UserPrincipal 和 UserDetailsService 的工作实现,它在默认登录设置上完美运行。如果需要,很高兴分享该代码。但在这一点上,我看不出会出什么问题。
如果有人想查看 UserDetailsService 和 UserDetails 代码,也包括在内:
@Service
public class EmployeeDetailsService implements UserDetailsService {
@Override
/*
* First, we are testing the Employee details service, independent of the Database, just to make sure we have this part working,
* For the purpose of these prototypes, we wont use password encoder because we are not registering,
*
* */
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (!username.equals("Mama")){
throw new UsernameNotFoundException("You got the wrong Username, should be mama");
}
Employee employee = new Employee();
Role role = new Role();
role.setName("HEAD");
employee
.setUsername(username)
.setPassword("1234")
.setRole(role);
return new EmployeePrincipal(employee);
}
}
public class EmployeePrincipal implements UserDetails {
private Employee employee;
public EmployeePrincipal(Employee employee){
this.employee = employee;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(employee.getRole().getName()));
return authorities;
}
@Override
public String getPassword() {
return employee.getPassword();
}
@Override
public String getUsername() {
return employee.getUsername();
}
/*
* Methods below are the rubbish methods, we keep as true for now
*
* */
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
请参阅网络附加的图片,我不明白发生了什么?POST 请求将 302 重定向回带有 200 状态代码的“/”?
无论天气如何,凭据是对还是错,这种情况都会发生
任何意见,将不胜感激
解决方案
CSRF 需要使用自定义表单来实现,因此对于测试和开发,最好禁用 CSRF
protected void configure(HttpSecurity http) throws Exception {
//Disabled for development
http.authorizeRequests()
.antMatchers("/mama").hasAuthority("MAMA")
.antMatchers("/home").hasAnyAuthority("HEAD", "MAMA")
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin()
.loginPage("/").permitAll()
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home")
.and()
.logout()
.logoutSuccessUrl("/");
}
推荐阅读
- flutter - 盒子上的资产图像
- asp.net-core - 有没有办法在 bootstrap/razor 中将值表示为星星?
- flutter - 当我从背景颤动进入前台时,showDialog 不可见
- python - 使用应用 lambda 函数根据另一列的条件创建一个新列
- functional-programming - 无论如何要及时获取列表的第 i 个元素 o(1) 标准 ML
- r - 如何在特定文本匹配中替换 R 中的值 NA
- html - 如何只为flex中的两个元素制作显示内联块?
- flutter - Flutter中的ListView用json数据实现
- node.js - model.predict.print() 未在 tensorflow.js 中显示所有结果
- javascript - 单击按钮时如何创建多个标签?当它们太多时,如何使它们消失?