一、自动配置分析

boot对security自动配置源于SpringBootWebSecurityConfiguration类

@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
//对所有http请求需要认证才能访问 ,支持表单认证和basic认证 ,这就是为什么引入依赖就对所有的资源进行包含 http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
return http.build();
}
}

这个类什么时候才生效,进入注解ConditionalOnDefaultWebSecurity

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(DefaultWebSecurityCondition.class)
public @interface ConditionalOnDefaultWebSecurity {

}

进入注解DefaultWebSecurityCondition满足下面两种情况则默认配置会生效,
1、有SecurityFilterChain类(只要引入security就有)
2、没有WebSecurityConfigurerAdapter类实列和SecurityFilterChain类实列

class DefaultWebSecurityCondition extends AllNestedConditions {

DefaultWebSecurityCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}

@ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
static class Classes {

}

//可以通过覆盖WebSecurityConfigurerAdapter和SecurityFilterChain对security配置进行扩展,一般用WebSecurityConfigurerAdapter,如果改SecurityFilterChain就用覆盖SecurityFilterChain
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
static class Beans {
}
}

分析默认配置类SpringBootWebSecurityConfiguration,满足下面两种情况则默认配置会生效,

  • 有SecurityFilterChain类(只要引入security就有)
  • 没有WebSecurityConfigurerAdapter类实列和SecurityFilterChain类实列

所以要修改security默认配置,我们只需要自定义一个类继承WebSecurityConfigurerAdapter即可

二、修改默认配置

1、前端后不分离

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//=================资源拦截=============
.mvcMatchers("/user/login").permitAll()//permitAll()表示放行资源 无需认证就可访问 必须放在所有认证前
.anyRequest().authenticated()//anyRequest()所有请求 .authenticated()表示所有请求需要认证才能访问
.and().formLogin() //formLogin()表示表单认证

//=================登录界面配置=================
.loginPage("/user/toLoginPage")//自定义访问登录页面地址
.loginProcessingUrl("/doLogin")//自定义登录请求的url
.usernameParameter("name")//自定义用户名、密码变量名
.passwordParameter("pass")

//=================认证配置=================
.successForwardUrl("/index")//认证成功始终跳转的路径.defaultSuccessUrl("/hello") redirect 重定向跳转 但是优先跳转到请求的路径 ,可以传入第二个参数true总是重定向到hello
.failureForwardUrl("/user/toLoginPage")//认证失败 跳转 错误信息在request中,.failureUrl("/login.html")认证失败 redirect跳转 错误信息在session中

//=================注销相关配置==========================
.and().logout()//开启注销,默认是配置的
/*满足任意一个就行(AndRequestMatcher同时满足) 可以是get也可以是post
.logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/logout1","GET"),
new AntPathRequestMatcher("/logout","POST")
))*/
.logoutUrl("/user/logout")//注销地址,默认是logout 并且请求方式只能是get
.invalidateHttpSession(true)//清除session信息,默认true
.clearAuthentication(true)//清除认证信息,默认true
.logoutSuccessUrl("/user/toLoginPage")//退出,默认是登录页面地址

.and().csrf().disable();
}
}

2、前后端分离配置

配置

@Configuration
public class MySecurityConfig1 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//=================资源拦截=============
.mvcMatchers("/user/login").permitAll()
.anyRequest().authenticated()
.and().formLogin()

//=================登录认证=================
.loginProcessingUrl("/doLogin")
.usernameParameter("name")
.passwordParameter("pass")
.successHandler(new MyAuthenticationSuccessHandler())//登录成功 自定义逻辑处理
.failureHandler(new MFailureHandler())//登录失败 自定义逻辑处理

//=================注销相关配置==========================
.and().logout()
.logoutUrl("/user/logout")
.logoutSuccessHandler(new MyLogoutSuccessUrl())//自定义注销成功处理器

.and().csrf().disable();
}
}

定义登录成功的逻辑处理器

/**
* 定义登录成功的逻辑处理器
*/
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map<String,Object> map = new HashMap<>();
map.put("code","200");
map.put("msg","success");
//认证信息
map.put("authentication",authentication);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(map));
}
}

自定登录失败处理器

/**
* 自定义认证失败处理器
*/
public class MFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
Map<String,Object> map = new HashMap<>();
map.put("code","500");
map.put("msg","success");
//认证信息
map.put("exception",exception);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(map));
}
}

自定义注销处理器

/**
* 自定义注销成功后逻辑处理
*/
public class MyLogoutSuccessUrl implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map<String,Object> map = new HashMap<>();
map.put("code","200");
map.put("msg","success");
//认证信息
map.put("authentication",authentication);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(map));
}
}