Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。 Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。像所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求
官方文档参考
当你看到这个登陆页面时,说明你在SpringBoot中整合SpringSecurity已经成功了 但是我们并没有在项目中设置用户名和密码 ,也没有写 /login ;但是别忘了我们引入了SpringSecurity, 如果我们没有进行SpringSecurity配置的话,它在启动时就会默认配置(源码截图如下) 默认用户名 user ,查看我们启动日志SpringSecurity还随机生成了一串密码: 输入用户名和密码: 我们成功访问到 /user/hello :
注: 配置文件配置的用户名和密码始终是通过 set 方法注入到属性中去
spring.security.user.name=zcc spring.security.user.password=123重启项目,输入我们自定义的用户名和密码,也成功访问到 /user/hello
自定义一个 Spring Security 的配置类,继承 WebSecurityConfigurerAdapter 类:
重写 configure(AuthenticationManagerBuilder auth) 方法,配置用户名,密码,角色
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder passwordEncoder(){ return NoOpPasswordEncoder.getInstance();//不加密 } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("zhangsan").password("123"); } }重启项目后,通过上面用户和密码也可成功访问到 /user/hello
通过上面自定义配置类也可以为用户配置角色及配置多用户 :
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() //开启在内存中定义用户 .withUser("zhangsan").password("123").roles("admin") //用户名 密码 角色 .and() //配置多个用户,用 and 相连 .withUser("zhangsan2").password("123").roles("user"); }重写 configure(WebSecurity web) 来配置忽略掉的 URL 地址,一般是配置忽略静态文件 :
@Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/js/**", "/css/**","/images/**"); }然后我们改造一下我们的 UserController 方便我们测试配置的用户角色 :
@RestController @RequestMapping("/user") public class UserController { @RequestMapping("/hello") public String hello(){ return "Hello SpringSecurity!"; } @RequestMapping("/admin") public String admin(){ return "你有admin角色"; } @RequestMapping("/user") public String user(){ return "你有user角色"; } }重写 configure(HttpSecurity http) 进行登陆配置
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护) .antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问 .antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问 .and().formLogin(); }重启项目,我们用拥有 admin 角色的用户: zhangsan 登陆访问 /admin/hello 和 /hello 都访问成功 访问 /user/hello 看到这个 表明他没有这个访问权限,同理用户: zhangsan2 ,也是不能访问 /admin/hello 但是如果做前后端分离,用postman测试,如果我们的请求方式不是 get 请求时,也会给我们报 403 : 然后我百度了一下,说的是从Spring Security 4.0开始,默认情况下会启用CSRF保护,以防止CSRF攻击应用程序,Spring Security CSRF会针对PATCH,POST,PUT和DELETE方法进行防护。 然后我们 禁用CSRF保护
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护) .antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问 .antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问 .and().formLogin() .and().csrf().disable() ; //禁用CSRF保护(支持跨域) }重启项目,用postman 登陆后就可以正常访问了 但是登陆成功后我们会发现给我们返回了 404 : 为什么会出现这种情况呢?肯定有的小伙伴会说我知道还用问你呀,那是我们从头到尾就没有哪个地方写过登陆成功或失败的返回,好了废话不多说上代码:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护) .antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问 .antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问 .and().formLogin() .successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter out = httpServletResponse.getWriter(); out.write(new ObjectMapper().writeValueAsString("登陆成功!")); out.flush(); out.close(); } }) .failureHandler(new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter out = httpServletResponse.getWriter(); out.write(new ObjectMapper().writeValueAsString("登陆失败!")); out.flush(); out.close(); } }) .and().csrf().disable(); //禁用CSRF保护 }有人肯定又有话要说了 JDK1.8 的 Lambda 表达式 用起来不香吗,还用这个,马上安排:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护) .antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问 .antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问 .and().formLogin() .successHandler((httpServletRequest, httpServletResponse, authentication) -> { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter out = httpServletResponse.getWriter(); out.write(new ObjectMapper().writeValueAsString("登陆成功!")); out.flush(); out.close(); }) .failureHandler((httpServletRequest, httpServletResponse, e) -> { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter out = httpServletResponse.getWriter(); out.write(new ObjectMapper().writeValueAsString("登陆失败!")); out.flush(); out.close(); }) .and().csrf().disable(); //禁用CSRF保护 }重启项目,登陆: 那么登陆有了,注销怎么弄呢?直接上代码:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //授权配置(启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护) .antMatchers("/admin/**").hasRole("admin") //配置/admin/**接口,拥有admin角色的可访问 .antMatchers("/user/**").hasRole("user") //配置/user/**接口,拥有user角色的可访问 .and().formLogin() .successHandler((httpServletRequest, httpServletResponse, authentication) -> { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter out = httpServletResponse.getWriter(); out.write(new ObjectMapper().writeValueAsString("登陆成功!")); out.flush(); out.close(); }) .failureHandler((httpServletRequest, httpServletResponse, e) -> { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter out = httpServletResponse.getWriter(); out.write(new ObjectMapper().writeValueAsString("登陆失败!")); out.flush(); out.close(); }) .and().logout() .logoutSuccessHandler((httpServletRequest, httpServletResponse, e) -> { httpServletResponse.setContentType("application/json;charset=utf-8"); PrintWriter out = httpServletResponse.getWriter(); out.write(new ObjectMapper().writeValueAsString("注销成功!")); out.flush(); out.close(); }) .and().csrf().disable(); //禁用CSRF保护 }走起: 好了,到这里我们SpringBoot整合SpringSecurity的入门级(基于内存用户名和密码的登陆,登出)操作就完成了
本博客是博主一字一字手敲出来的 , 如果大家觉得我哪里有不对的地方,欢迎大家在评论区给我指出来