当前位置: 首页 > news >正文

SpringSecurity入门(一)

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";}
}
  • 启动

image.png

  • 访问http://localhost:8080/

image.png

  • 登陆使用账号:user,密码:04e74f23-0e97-4ee9-957e-2004a2e60692

image.png

  • SecurityProperties

image.png

3、自动配置SpringBootWebSecurityConfiguration

  • SecurityFilterChainConfiguration

image.png

  • WebSecurityConfigurerAdapter中有所有的Security相关的配置,只需要继承重新对应属性即可完成自定义
  • 由于新版本的Security已经弃用WebSecurityConfigurerAdapter所以注册SecurityFilterChain即可
  @BeanSecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {return httpSecurity.authorizeRequests().mvcMatchers("/index").permitAll().anyRequest().authenticated().and().formLogin().and().build();}

image.png

4、默认登陆页面DefaultLoginPageGeneratingFilter

image.png

4.1、SecurityFilterChainConfiguration默认实现的SecurityFilterChain

  • 容器中没有WebSecurityConfigurerAdapter类型的bean实例自动配置才会生效

image.png

4.2、UsernamePasswordAuthenticationFilter

image.png

4.3、attemptAuthentication方法

image.png

4.4、 ProviderManager的authenticate方法

image.png

4.5、 AuthenticationProvider实现AbstractUserDetailsAuthenticationProvider中的authenticate方法

image.png

4.6、 UserDetails实现类DaoAuthenticationProvider的retrieveUser方法

image.png

4.7、UserDetailsService实现类InMemoryUserDetailsManager的loadUserByUsername方法

image.png

4.8、 UserDetailsService

image.png

4.9、 UserDetailsServiceAutoConfiguration

image.png

  • 容器中没有:AuthenticationManager、AuthenticationProvider、UserDetailsService、AuthenticationManagerResolver这4个bean实例才会加载InMemoryUserDetailsManager

image.png
image.png

4.10、 SecurityProperties

image.png
image.png
image.png

  • 可以通过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的方式提交

image.png

<!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

image.png

5.3、 自定义认证成功后访问的页面

  • successForwardUrl(转发),必须使用POST请求,每次都会跳转到指定请求
  • defaultSuccessUrl(重定向),必须使用GET请求,不会每次都跳转定义的页面,默认会记录认证拦截的请求,如果是拦截的受限资源会优先跳转到之前被拦截的请求。需要每次都跳转使用.defaultSuccessUrl(“/test”,true)即可

image.png

  • 二选一
//               登陆认证成功后跳转的页面(转发),必须使用POST请求
//                .successForwardUrl("/test")
//               陆认证成功后跳转的页面(重定向),必须使用GET请求.defaultSuccessUrl("/test",true)

5.4、 前后端分离处理方式

image.png

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、返回数据

image.png

6、 认证失败处理

  • failureForwardUrl,转发,请求必须是POST
  • failureUrl,重定向,请求必须是GET

6.1、org.springframework.security.authentication.ProviderManager#authenticate

image.png

6.2、 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#doFilter(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)

image.png

6.3、 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#unsuccessfulAuthentication

image.png

6.4、 org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#onAuthenticationFailure

image.png

6.5、 org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#saveException

image.png

  • 如果是转发异常信息存在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、 前后端分离处理方式

image.png

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、 前后端分离

image.png

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入门(四)

未完待续

相关文章:

  • TOGAF架构介绍
  • 一文理解什么是k-近邻算法
  • 【网络安全的神秘世界】磁盘空间告急?如何解决“no space left on device”的困扰
  • day38 ● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯
  • 生活使用英语口语柯桥外语学校成人英语学习
  • HBase中Master初始化错误~
  • STM32无法烧写程序的故障排除
  • Flink的简单学习五
  • 鸿蒙开发:【线程模型】
  • 测试bert_base不同并行方式下的推理性能
  • STM32--DMA
  • Comfyui容器化部署与简介
  • mysql log_bin
  • Next.js 加载页面及流式渲染(Streaming)
  • 小公司要求真高
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • Angular2开发踩坑系列-生产环境编译
  • Asm.js的简单介绍
  • CSS3 变换
  • Java 内存分配及垃圾回收机制初探
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • JavaScript实现分页效果
  • Java方法详解
  • Linux gpio口使用方法
  • MySQL-事务管理(基础)
  • Swoft 源码剖析 - 代码自动更新机制
  • vue-router的history模式发布配置
  • vue中实现单选
  • 翻译:Hystrix - How To Use
  • 给新手的新浪微博 SDK 集成教程【一】
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 回顾2016
  • 深度学习在携程攻略社区的应用
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 通过git安装npm私有模块
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 一个项目push到多个远程Git仓库
  • ​马来语翻译中文去哪比较好?
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #{} 和 ${}区别
  • #define用法
  • #NOIP 2014# day.1 T2 联合权值
  • #pragam once 和 #ifndef 预编译头
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .NET 药厂业务系统 CPU爆高分析
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [2010-8-30]