目录
源码 auth.inMemoryAuthentication()
简介
Spring Security是针对Spring项目的安全框架,也是SpringBoot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
- WebSecurityConfigurerAdapter: 自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式
- 日后看见@Enablexxxx 就是开启某个功能
Spring Security的两个主要目标是“认证”和“授权”(访问控制)。
"认证”(Authentication)
"授权"(Authorization)
这个概念是通用的,而不是只在Spring Security中存在。参考官网:
注意:
SpringBoot支持Security 版本不超过 2.0.9
准备工作
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
RouterController
@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String toIndex(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
@RequestMapping("/level1/{id}")
public String toLevel1(@PathVariable("id")Integer id){
return "views/level1/"+id;
}
@RequestMapping("/level2/{id}")
public String toLevel2(@PathVariable("id")Integer id){
return "views/level2/"+id;
}
@RequestMapping("/level3/{id}")
public String toLevel3(@PathVariable("id")Integer id){
return "views/level3/"+id;
}
}
特别讲解:
@RequestMapping("/level1/{id}")
public String toLevel1(@PathVariable("id")Integer id){
return "views/level1/"+id;
}
一、授权
SecurityConfig---1.1
//AOP : 拦截器!
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权 链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问
//请求授权的规则
http.authorizeRequests().antMatchers("/","/index").permitAll() //首页所有人可以访问
.antMatchers("/level1/**").hasRole("vip1") //level1 下得所有页面 需要拥有 hasRole vip1 才可以访问
.antMatchers("/level2/**").hasRole("vip2") //level2 下得所有页面 需要拥有 hasRole vip2 才可以访问
.antMatchers("/level3/**").hasRole("vip3"); //level3 下得所有页面 需要拥有 hasRole vip3 才可以访问
}
}
SecurityConfig---1.2
//AOP : 拦截器!
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权 链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问
//请求授权的规则
http.authorizeRequests().antMatchers("/","/index").permitAll() //首页所有人可以访问
.antMatchers("/level1/**").hasRole("vip1") //level1 下得所有页面 需要拥有 hasRole vip1 才可以访问
.antMatchers("/level2/**").hasRole("vip2") //level2 下得所有页面 需要拥有 hasRole vip2 才可以访问
.antMatchers("/level3/**").hasRole("vip3"); //level3 下得所有页面 需要拥有 hasRole vip3 才可以访问
//没有权限 默认跳到登录页面
http.formLogin();
}
}
源码 formLogin
/**
* Specifies to support form based authentication. If
* {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page
* will be generated.
*
* <h2>Example Configurations</h2>
*
* The most basic configuration defaults to automatically generating a login page at
* the URL "/login", redirecting to "/login?error" for authentication failure. The
* details of the login page can be found on
* {@link FormLoginConfigurer#loginPage(String)}
*
* <pre>
* @Configuration
* @EnableWebSecurity
* public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
*
* @Override
* protected void configure(HttpSecurity http) throws Exception {
* http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin();
* }
*
* @Override
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
* }
* }
* </pre>
*
* The configuration below demonstrates customizing the defaults.
*
* <pre>
* @Configuration
* @EnableWebSecurity
* public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {
*
* @Override
* protected void configure(HttpSecurity http) throws Exception {
* http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin()
* .usernameParameter("username") // default is username
* .passwordParameter("password") // default is password
* .loginPage("/authentication/login") // default is /login with an HTTP get
* .failureUrl("/authentication/login?failed") // default is /login?error
* .loginProcessingUrl("/authentication/login/process"); // default is /login
* // with an HTTP
* // post
* }
*
* @Override
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
* }
* }
* </pre>
*
* @see FormLoginConfigurer#loginPage(String)
*
* @return the {@link FormLoginConfigurer} for further customizations
* @throws Exception
*/
public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
return getOrApply(new FormLoginConfigurer<>());
}
二、身份验证
核心类:Authentication 身份验证
注:
//认证 springboot 2.1.X 可以直接使用 //密码编码 PasswordEncoder //在spring Security 5.0+ 新增了很多的加密方法~
底部
SecurityConfig---2.1
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该从数据库中读取 jdbcAuthentication() 此时是 内存中读取inMemoryAuthentication
auth.inMemoryAuthentication()
.withUser("kuangshen").password("123456").roles("vip2","vip3")
.and()
.withUser("root").password("123456").roles("vip1","vip2","vip3")
.and()
.withUser("guest").password("123456").roles("vip1","vip3")
}
SecurityConfig---2.2
//认证 springboot 2.1.X 可以直接使用
//密码编码 PasswordEncoder
//在spring Security 5.0+ 新增了很多的加密方法~
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该从数据库中读取 jdbcAuthentication() 此时是 内存中读取inMemoryAuthentication
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) //密码加密的方式
.withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3") //编码
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
JDBC
源码 auth.inMemoryAuthentication()
三、注销 http.logout();
//AOP : 拦截器!
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权 链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问
//请求授权的规则
http.authorizeRequests().antMatchers("/","/index").permitAll() //首页所有人可以访问
.antMatchers("/level1/**").hasRole("vip1") //level1 下得所有页面 需要拥有 hasRole vip1 才可以访问
.antMatchers("/level2/**").hasRole("vip2") //level2 下得所有页面 需要拥有 hasRole vip2 才可以访问
.antMatchers("/level3/**").hasRole("vip3"); //level3 下得所有页面 需要拥有 hasRole vip3 才可以访问
//没有权限 默认跳到登录页面
http.formLogin();
//注销,开启了注销功能
http.logout();
}
}
http.logout().deleteCookies("remove").invalidateHttpSession(true);//移除所有的Cookie 清空所有的Session //注销 登出成功后跳转到 首页 http.logout().logoutSuccessUrl("/");
源码 http.logout();
/**
* Provides logout support. This is automatically applied when using
* {@link WebSecurityConfigurerAdapter}. The default is that accessing the URL
* "/logout" will log the user out by invalidating the HTTP Session, cleaning up any
* {@link #rememberMe()} authentication that was configured, clearing the
* {@link SecurityContextHolder}, and then redirect to "/login?success".
*
* <h2>Example Custom Configuration</h2>
*
* The following customization to log out when the URL "/custom-logout" is invoked.
* Log out will remove the cookie named "remove", not invalidate the HttpSession,
* clear the SecurityContextHolder, and upon completion redirect to "/logout-success".
*
* <pre>
* @Configuration
* @EnableWebSecurity
* public class LogoutSecurityConfig extends WebSecurityConfigurerAdapter {
*
* @Override
* protected void configure(HttpSecurity http) throws Exception {
* http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin()
* .and()
* // sample logout customization
* .logout().deleteCookies("remove").invalidateHttpSession(false)
* .logoutUrl("/custom-logout").logoutSuccessUrl("/logout-success");
* }
*
* @Override
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
* }
* }
* </pre>
*
* @return the {@link LogoutConfigurer} for further customizations
* @throws Exception
*/
实例:
四、防止网站被攻击
//防止网站攻击工具 get post http.csrf().disable(); //关闭csrf 功能 登出失败 可能存在的原因
五、权限登录---根据不同的用户显示不同的版块
Security—thymeleaf整合
<!--Security———thymeleaf 整合-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
作用: 在 thymeleaf 中可以写一些 Security 的操作
1.导入命名空间
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
2. 上面隐藏
<!--登录注销-->
<div class="right menu">
<!--未登录 显示登录页面 authorize v. 批准,许可;授权 -->
<div sec:authorize="!isAuthenticated()"> <!--!isAuthenticated()未登录-->
<a class="item" th:href="@{/toLogin}">
<i class="address card icon"></i> 登录
</a>
</div>
<!-- 已登录 显示注销和用户名 -->
<div sec:authorize="isAuthenticated()">
<a class="item">
用户名:<span sec:authentication="principal.username"></span>
权限:<span sec:authentication="principal.authorities"></span>
<!--角色:<span sec:authentication="principal.getPassword()"></span>-->
</a>
</div>
<div sec:authorize="isAuthenticated()">
<!--注销-->
<a class="item" th:href="@{/logout}">
<i class="sign-out icon"></i> 注销
</a>
</div>
</div>
3.下面隐藏
<!--根据用户的角色动态实现-->
<div class="column" sec:authorize="hasRole('vip1')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 1</h5>
<hr>
<div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
<div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
<div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
</div>
</div>
</div>
</div>
<div class="column" sec:authorize="hasRole('vip2')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 2</h5>
<hr>
<div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
<div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
<div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
</div>
</div>
</div>
</div>
<div class="column" sec:authorize="hasRole('vip3')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 3</h5>
<hr>
<div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
<div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
<div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
</div>
</div>
</div>
</div>
六、记住我功能
//记住我功能 cookie 默认保存两周 //rememberMeParameter 记住我的参数 http.rememberMe().rememberMeParameter("remember");
七、定制自己的登录页面
//定制自己的登录页面 http.formLogin().loginPage("/toLogin");
问题一:前后端页面请求url 不一致
方式一: 修改前后端修改一致
方式二: loginProcessingUrl
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");
问题二: 前后端传递参数不一致
//前后端 传递的参数不一致 默认 username password
http.formLogin().loginPage("/toLogin")
.usernameParameter("user")
.passwordParameter("pwd").loginProcessingUrl("/login");
SecurityConfig
/**
* Security配置文件
*/
//AOP : 拦截器!
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权 链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问
//请求授权的规则
http.authorizeRequests().antMatchers("/","/index").permitAll() //首页所有人可以访问
.antMatchers("/level1/**").hasRole("vip1") //level1 下得所有页面 需要拥有 hasRole vip1 才可以访问
.antMatchers("/level2/**").hasRole("vip2") //level2 下得所有页面 需要拥有 hasRole vip2 才可以访问
.antMatchers("/level3/**").hasRole("vip3"); //level3 下得所有页面 需要拥有 hasRole vip3 才可以访问
//没有权限 默认跳到登录页面
http.formLogin();
//定制自己的登录页面
// 方式一:
// http.formLogin().loginPage("/toLogin"); 网页请求写 toLogin
// 问题一: loginProcessingUrl 登录认证的是那个url 网页写 login
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");
// 问题二: 前后端 传递的参数不一致 默认 username password
// http.formLogin().loginPage("/toLogin")
// .usernameParameter("user")
// .passwordParameter("pwd").loginProcessingUrl("/login");
//注销 登出成功后跳转到index.html
http.logout();
//注销 登出成功后跳转到 首页
http.logout().logoutSuccessUrl("/");
//防止网站攻击工具 get post
http.csrf().disable(); //关闭csrf 功能 登出失败 可能存在的原因
//记住我功能 cookie 默认保存两周
//rememberMeParameter 记住我的参数
http.rememberMe().rememberMeParameter("remember");
// //定制首页可以随意访问 另一种方式
// http.authorizeRequests().antMatchers("/","/index").permitAll();
//
// //level1页面:vip1 2 3 都可以访问该页面
// http.authorizeRequests().antMatchers("/level1/**").hasRole("vip1");
//
// //level2页面:vip2 3可以访问
// http.authorizeRequests().antMatchers("/level2/**").hasRole("vip2");
//
// //level3页面:vip3才能访问
// http.authorizeRequests().antMatchers("/level3/**").hasRole("vip3");
}
//认证 springboot 2.1.X 可以直接使用
//密码编码 PasswordEncoder
//在spring Security 5.0+ 新增了很多的加密方法~
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该从数据库中读取 jdbcAuthentication() 此时是 内存中读取inMemoryAuthentication
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) //密码加密的方式
.withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3") //编码
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
RouterController
@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String toIndex(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
@RequestMapping("/level1/{id}")
public String toLevel1(@PathVariable("id")Integer id){
return "views/level1/"+id;
}
@RequestMapping("/level2/{id}")
public String toLevel2(@PathVariable("id")Integer id){
return "views/level2/"+id;
}
@RequestMapping("/level3/{id}")
public String toLevel3(@PathVariable("id")Integer id){
return "views/level3/"+id;
}
}