package com.tho.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* Spring Security配置
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//表单提交
http.formLogin()
//自定义登录页面
.loginPage("/loginPage")
//必须和表单提交的接口路径一致,会去执行自定义登录逻辑
.loginProcessingUrl("/login")
//登录成功后跳转到的页面,只接受post请求
.successForwardUrl("/main");
//授权
http.authorizeRequests()
//放行的路径
.antMatchers("/login.html","/loginPage").permitAll()
//除了放行路径,其他路径都需要授权
.anyRequest().authenticated();
//关闭csrf防护
http.csrf().disable();
}
/** 向容器中注入PasswordEncoder实例*/
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
通过继承重写父类方法!!
依旧是访问:localhost:8686
当我们访问后被拦截,必须要登录,因为我们在放行的路径中,只放行了,Login页面,以及请求Login页面的方法。访问主页的方法我们并没有给。
不匹配我们规则的登录,验证失败,可见url后缀是确实带有错误的标识。
同样的我们使用符合UserDetailsService里面的规则去登录:
切记如果使用string作为方法的返回类型请切记参数中必须要有model对象,否则就无法重定向成功。当然也可以使用ModelAndView对象。
到此我们发现我们实际上没有写和post请求相关的内容,我们却可以正常登录,实际上是框架帮我们做了,但是我们业务往往要求的是灵活,像参数等等,很难说那么固定,那么如果要自定义怎么处理呢?
看看源码:
写死了,请求方式还有声明入参等等,如果不是post就会抛出异常。咋一看好像参数无法自定义,其实不然,继续仔细看源码:
成员声明了初始值,但是并没有用final修饰,而通过代码我们可以看出,其可以通过set方法,修改值,然后再走的三目运算。ok那么就试试。
如果跟着做的朋友应该会发现,其实我们已经定义了成功返回的url,但是为什么路径是Login呢
其实是因为我们跳的页面是没错,但是url没变,因为成功后是转发。
上面的写法存在一点问题,修正到如下即可,第一次
这样写的原因是因为SpringSecurity的登录成功处理器没有重定向的方式,所以我们把重定向这个任务交给SpringMVC来做,发两次请求,成功了就发/请求,/又重定向/main请求,main渲染main.html就完成了。
当然这是解决方法之一,还有一种呢则是继承接口编写一个自定义的重定向处理器,如果我们想做,让他登录成功了直接访问外链的话,这个是必不可少的。
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义登录成功后的处理器
*/
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private String url;
// 构造方法
public MyAuthenticationSuccessHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// 获取用户
User user = (User) authentication.getPrincipal();
// 打印用户名
System.out.println(user.getUsername());
// 密码,出于安全考虑,Spring Security这里会返回一个Null
System.out.println(user.getPassword());
// 权限
System.out.println(user.getAuthorities());
// 这里使用跳转
response.sendRedirect(url);
}
}
成功,我们再换一下哔哩哔哩试试
很好这就完成了登录成功自定义后页面的跳转
当然本站内,觉得发两次请求有点奇怪,那么可以使用框架带有的SimpleUrlAuthenticationSuccessHandler
在配置中.loginProcessingUrl("/Login")后继续
.successHandler(new SimpleUrlAuthenticationSuccessHandler("/main"))
可以实现和上面一样的效果。
和上面一样,是失败也有自己的处理器,和成功是对应的。
同样的可以自定义处理器:
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义失败登录跳转处理器
*/
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
private String url;
// 构造方法
public MyAuthenticationFailureHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
// 失败登录后使用重定向
response.sendRedirect(url);
}
}