1、引入依赖
spring-boot版本2.7.3,如未特殊说明版本默认使用此版本
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</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-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency>
2、编写controller并启动springboot服务
@RestController
public class HelloController {@GetMapping("/")public String hello(){return "hello SpringSecurity";}
}
- 启动
- 访问http://localhost:8080/
- 登陆使用账号:user,密码:04e74f23-0e97-4ee9-957e-2004a2e60692
- SecurityProperties
3、自动配置SpringBootWebSecurityConfiguration
- SecurityFilterChainConfiguration
- WebSecurityConfigurerAdapter中有所有的Security相关的配置,只需要继承重新对应属性即可完成自定义
- 由于新版本的Security已经弃用WebSecurityConfigurerAdapter所以注册SecurityFilterChain即可
@BeanSecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return httpSecurity.authorizeRequests().mvcMatchers("/index").permitAll().anyRequest().authenticated().and().formLogin().and().build();}
4、默认登陆页面DefaultLoginPageGeneratingFilter
4.1、SecurityFilterChainConfiguration默认实现的SecurityFilterChain
- 容器中没有WebSecurityConfigurerAdapter类型的bean实例自动配置才会生效
4.2、UsernamePasswordAuthenticationFilter
4.3、attemptAuthentication方法
4.4、 ProviderManager的authenticate方法
4.5、 AuthenticationProvider实现AbstractUserDetailsAuthenticationProvider中的authenticate方法
4.6、 UserDetails实现类DaoAuthenticationProvider的retrieveUser方法
4.7、UserDetailsService实现类InMemoryUserDetailsManager的loadUserByUsername方法
4.8、 UserDetailsService
4.9、 UserDetailsServiceAutoConfiguration
- 容器中没有:AuthenticationManager、AuthenticationProvider、UserDetailsService、AuthenticationManagerResolver这4个bean实例才会加载InMemoryUserDetailsManager
4.10、 SecurityProperties
- 可以通过spring.security.user.password=123456自定义密码
5、 自定义认证
5.1、由于新版本的Security已经弃用WebSecurityConfigurerAdapter所以注册SecurityFilterChain即可
github示例
@BeanSecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return httpSecurity.authorizeRequests().mvcMatchers("/index").permitAll().anyRequest().authenticated().and().formLogin().and().build();}
5.2、 自定义登陆页面
5.2.1、html
- 使用UsernamePasswordAuthenticationFilter用户名和密码字段名必须是username和password,且必须是POST的方式提交
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head><meta charset="UTF-8"><title>login</title>
</head>
<body>
<form th:action="@{/doLogin}" method="post"><p>用户名:<label><input name="username" type="text"/></label></p><p>密码:<label><input name="password" type="password"/></label></p><p><input type="submit"></p>
</form></body>
</html>
5.2.2、SecurityFilterChain配置
@Configuration
public class WebSecurityConfigurer {@BeanSecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin").and()//禁止csrf跨站请求保护.csrf().disable().build();}
5.2.3、 controller
@Controller
public class LoginController {@RequestMapping("toLogin")public String toLogin(){return "login";}
}
5.2.4、 自定义登陆使用的用户名和密码字段名使用usernameParameter和passwordParameter
@Configuration
public class WebSecurityConfigurer {@BeanSecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin")
// 自定义接收用户名的参数名为uname.usernameParameter("uname")
// 自定义接收密码的参数名为pwd.passwordParameter("pwd").and()//禁止csrf跨站请求保护.csrf().disable().build();}
}
- form表单中对应参数名也需要修改,用户名为:uname,密码为:pwd
5.3、 自定义认证成功后访问的页面
- successForwardUrl(转发),必须使用POST请求,每次都会跳转到指定请求
- defaultSuccessUrl(重定向),必须使用GET请求,不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使用.defaultSuccessUrl(“/test”,true)即可
- 二选一
// 登陆认证成功后跳转的页面(转发),必须使用POST请求
// .successForwardUrl("/test")
// 陆认证成功后跳转的页面(重定向),必须使用GET请求.defaultSuccessUrl("/test",true)
5.4、 前后端分离处理方式
5.4.1、 实现AuthenticationSuccessHandler接口
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {Map<String,Object> map = new HashMap<>();map.put("msg", "登陆成功");map.put("code", HttpStatus.OK);map.put("authentication", authentication);String s = new ObjectMapper().writeValueAsString(map);response.setContentType("application/json;charset=UTF-8");response.getWriter().write(s);}
}
5.4.2、修改SecurityFilterChain配置
- 使用successHandler(new MyAuthenticationSuccessHandler())
@Configuration
public class WebSecurityConfigurer {@Bean@SuppressWarnings("all")SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin")
// 自定义接收用户名的参数名为uname.usernameParameter("uname")
// 自定义接收密码的参数名为pwd.passwordParameter("pwd")
// 登陆认证成功后跳转的页面(转发),必须使用POST请求
// .successForwardUrl("/test")
// 陆认证成功后跳转的页面(转发),必须使用GET请求
// .defaultSuccessUrl("/test",true)//不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使defaultSuccessUrl("/test",true)
// .defaultSuccessUrl("/test")
// 前后端分离时代自定义认证成功处理.successHandler(new MyAuthenticationSuccessHandler()).and()//禁止csrf跨站请求保护.csrf().disable().build();}
}
5.4.3、返回数据
6、 认证失败处理
- failureForwardUrl,转发,请求必须是POST
- failureUrl,重定向,请求必须是GET
6.1、org.springframework.security.authentication.ProviderManager#authenticate
6.2、 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#doFilter(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
6.3、 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#unsuccessfulAuthentication
6.4、 org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#onAuthenticationFailure
6.5、 org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#saveException
- 如果是转发异常信息存在request里面
- 如果是重定向异常信息存在session里面,默认是重定向
- 参数名:SPRING_SECURITY_LAST_EXCEPTION
6.7、 前端取值展示
- 修改SecurityFilterChain配置
@Configuration
public class WebSecurityConfigurer {@Bean@SuppressWarnings("all")SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin")
// 自定义接收用户名的参数名为uname.usernameParameter("uname")
// 自定义接收密码的参数名为pwd.passwordParameter("pwd")
// 登陆认证成功后跳转的页面(转发),必须使用POST请求
// .successForwardUrl("/test")
// 陆认证成功后跳转的页面(转发),必须使用GET请求
// .defaultSuccessUrl("/test",true)//不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使defaultSuccessUrl("/test",true)
// .defaultSuccessUrl("/test")
// 前后端分离时代自定义认证成功处理.successHandler(new MyAuthenticationSuccessHandler())
// 认证失败跳转页面,必须使用POST请求 .failureForwardUrl("/toLogin")// 认证失败跳转页面,,必须使用GET请求// .failureUrl("/toLogin").and()//禁止csrf跨站请求保护.csrf().disable().build();}
}
- html增加取值
<!-- 重定向错误信息存在session中 -->
<p th:text="${session.SPRING_SECURITY_LAST_EXCEPTION}"></p>
<!-- 转发错误信息存在request中 -->
<p th:text="${SPRING_SECURITY_LAST_EXCEPTION}"></p>
6.8、 前后端分离处理方式
6.8.1、 实现AuthenticationFailureHandler接口
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {Map<String,Object> map = new HashMap<>();map.put("msg", exception.getMessage());map.put("code", HttpStatus.INTERNAL_SERVER_ERROR.value());String s = new ObjectMapper().writeValueAsString(map);response.setContentType("application/json;charset=UTF-8");response.getWriter().write(s);}
}
6.8.2、修改SecurityFilterChain配置
- failureHandler
@Configuration
public class WebSecurityConfigurer {@Bean@SuppressWarnings("all")SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin")
// 自定义接收用户名的参数名为uname.usernameParameter("uname")
// 自定义接收密码的参数名为pwd.passwordParameter("pwd")
// 登陆认证成功后跳转的页面(转发),必须使用POST请求
// .successForwardUrl("/test")
// 陆认证成功后跳转的页面(转发),必须使用GET请求
// .defaultSuccessUrl("/test",true)//不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使defaultSuccessUrl("/test",true)
// .defaultSuccessUrl("/test")
// 前后端分离时代自定义认证成功处理.successHandler(new MyAuthenticationSuccessHandler())
// 认证失败跳转页面,必须使用POST请求
// .failureForwardUrl("/toLogin")
// 认证失败跳转页面,必须使用GET请求
// .failureUrl("/toLogin")
// 前后端分离时代自定义认证失败处理.failureHandler(new MyAuthenticationFailureHandler()).and()//禁止csrf跨站请求保护.csrf().disable().build();}
}
7、 注销登录
7.1、 默认方式
.logout()
// 指定注销url,默认请求方式GET
.logoutUrl(“/logout”)
// 注销成功后跳转页面
.logoutSuccessUrl(“/toLogin”)
@Configuration
public class WebSecurityConfigurer {@Bean@SuppressWarnings("all")SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin")
// 自定义接收用户名的参数名为uname.usernameParameter("uname")
// 自定义接收密码的参数名为pwd.passwordParameter("pwd")
// 登陆认证成功后跳转的页面(转发),必须使用POST请求
// .successForwardUrl("/test")
// 陆认证成功后跳转的页面(转发),必须使用GET请求
// .defaultSuccessUrl("/test",true)//不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使defaultSuccessUrl("/test",true)
// .defaultSuccessUrl("/test")
// 前后端分离时代自定义认证成功处理.successHandler(new MyAuthenticationSuccessHandler())
// 认证失败跳转页面,必须使用POST请求
// .failureForwardUrl("/toLogin")
// 认证失败跳转页面,必须使用GET请求
// .failureUrl("/toLogin")
// 前后端分离时代自定义认证失败处理.failureHandler(new MyAuthenticationFailureHandler()).and()
// 注销.logout()
// 指定注销url,默认请求方式GET.logoutUrl("/logout")
// 销毁session,默认为true.invalidateHttpSession(true)
// 清除认证信息,默认为true.clearAuthentication(true)
// 注销成功后跳转页面.logoutSuccessUrl("/toLogin").and()//禁止csrf跨站请求保护.csrf().disable().build();}
}
7.2、 自定义方式
// 注销
.logout()
// 自定义注销url
.logoutRequestMatcher(newOrRequestMatcher(
newAntPathRequestMatcher(“/aa”,“GET”),
newAntPathRequestMatcher(“/bb”,“POST”)
))
// 注销成功后跳转页面
.logoutSuccessUrl(“/toLogin”)
@Configuration
public class WebSecurityConfigurer {@Bean@SuppressWarnings("all")SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin")
// 自定义接收用户名的参数名为uname.usernameParameter("uname")
// 自定义接收密码的参数名为pwd.passwordParameter("pwd")
// 登陆认证成功后跳转的页面(转发),必须使用POST请求
// .successForwardUrl("/test")
// 陆认证成功后跳转的页面(转发),必须使用GET请求
// .defaultSuccessUrl("/test",true)//不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使defaultSuccessUrl("/test",true)
// .defaultSuccessUrl("/test")
// 前后端分离时代自定义认证成功处理.successHandler(new MyAuthenticationSuccessHandler())
// 认证失败跳转页面,必须使用POST请求
// .failureForwardUrl("/toLogin")
// 认证失败跳转页面,必须使用GET请求
// .failureUrl("/toLogin")
// 前后端分离时代自定义认证失败处理.failureHandler(new MyAuthenticationFailureHandler()).and()
// 注销.logout()
// 指定注销url,默认请求方式GET
// .logoutUrl("/logout").logoutRequestMatcher(new OrRequestMatcher(new AntPathRequestMatcher("/aa","GET"),new AntPathRequestMatcher("/bb","POST")))
// 销毁session,默认为true.invalidateHttpSession(true)
// 清除认证信息,默认为true.clearAuthentication(true)
// 注销成功后跳转页面.logoutSuccessUrl("/toLogin").and()//禁止csrf跨站请求保护.csrf().disable().build();}
}
7.3、 前后端分离
7.3.1、 实现LogoutSuccessHandler接口
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {Map<String,Object> map = new HashMap<>();map.put("msg", "注销成功");map.put("code", HttpStatus.OK.value());map.put("authentication", authentication);String s = new ObjectMapper().writeValueAsString(map);response.setContentType("application/json;charset=UTF-8");response.getWriter().write(s);}
}
7.3.2、 修改SecurityFilterChain配置
- logoutSuccessHandler
@Configuration
public class WebSecurityConfigurer {@Bean@SuppressWarnings("all")SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return//开启权限验证httpSecurity.authorizeRequests()//permitAll直接放行,必须在anyRequest().authenticated()前面.mvcMatchers("/toLogin").permitAll().mvcMatchers("/index").permitAll()//anyRequest所有请求都需要认证.anyRequest().authenticated().and()//使用form表单验证.formLogin()//自定义登陆页面.loginPage("/toLogin")//自定义登陆页面后必须指定处理登陆请求的url.loginProcessingUrl("/doLogin")
// 自定义接收用户名的参数名为uname.usernameParameter("uname")
// 自定义接收密码的参数名为pwd.passwordParameter("pwd")
// 登陆认证成功后跳转的页面(转发),必须使用POST请求
// .successForwardUrl("/test")
// 陆认证成功后跳转的页面(转发),必须使用GET请求
// .defaultSuccessUrl("/test",true)//不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使defaultSuccessUrl("/test",true)
// .defaultSuccessUrl("/test")
// 前后端分离时代自定义认证成功处理.successHandler(new MyAuthenticationSuccessHandler())
// 认证失败跳转页面,必须使用POST请求
// .failureForwardUrl("/toLogin")
// 认证失败跳转页面,必须使用GET请求
// .failureUrl("/toLogin")
// 前后端分离时代自定义认证失败处理.failureHandler(new MyAuthenticationFailureHandler()).and()
// 注销.logout()
// 指定默认注销url,默认请求方式GET
// .logoutUrl("/logout")
// 自定义注销url.logoutRequestMatcher(new OrRequestMatcher(new AntPathRequestMatcher("/aa","GET"),new AntPathRequestMatcher("/bb","POST")))
// 销毁session,默认为true.invalidateHttpSession(true)
// 清除认证信息,默认为true.clearAuthentication(true)
// 注销成功后跳转页面
// .logoutSuccessUrl("/toLogin").logoutSuccessHandler(new MyLogoutSuccessHandler()).and()//禁止csrf跨站请求保护.csrf().disable().build();}
}
相关文章
SpringSecurity入门(二)
SpringSecurity入门(三)
SpringSecurity入门(四)
未完待续