SpringBoot-SpringSecurity
简介
Spring Security是一个基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。对于安全控制,我们仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
- WebSecurityConfigurerAdapter:自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式
Spring Security的两个主要目标是“认证”和“授权”(访问控制)。
“认证”(Authentication)
“授权”(Authorization)
这个概念是通用的,而不是只在Spring Security中存在。
参考官网:https://docs.spring.io/spring-security,找到对应的帮助文档:https://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle
如何使用
导入依赖
<!--spring-security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
功能实现:用户认证和授权
package com.kuang.config;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
//AOP:拦截器!不用改变任何代码就能实现操作
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问
//请求【授权】的规则
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//没有权限默认会到登录页面,需要开启登录的页面
// /login
http.formLogin();
//注销
http.logout();
}
//【认证】
//密码编码
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该从数据库中读,此处是在内存中读取数据
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("lqc").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
//【认证】
//在数据库中读取数据模板
@Autowired
private DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// ensure the passwords are encoded properly
UserBuilder users = User.withDefaultPasswordEncoder();
auth
.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema()
.withUser(users.username("user").password("password").roles("USER"))
.withUser(users.username("admin").password("password").roles("USER","ADMIN"));
}
功能实现:注销及权限控制
- 在同上安全配置类中(SecurityConfig)授权中加入
//如果注销失败了,可能就是因为开启了csrf把它关掉
http.csrf().disable();//关闭csrf功能,登录失败存在的原因,因为csrf不支持post
//注销之后返回首页
http.logout().logoutSuccessUrl("/");
- 此时我们ctrl+b(logout)看一下源码,
2.1. 如果发现出现Sources not found for: org.springframework警告,打开不了源码。
于是,百度,解决方案如下:
【此处参考:https://blog.csdn.net/CSDN877425287/article/details/113923048】
并执行如下命令:
mvn dependency:resolve -Dclassifier=sources
此时就可下载源码了
3. 看源码的时候,发现
* "/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".
也就是说,通过/logout路径可注销用户,并清理任何已配置的身份验证
4. 在index.html首页中,加入
<a class="item" th:href="@{/logout}">
<i class="sign-out icon"></i> 注销
</a>
5.权限控制:
控制上面菜单思路:当登录成功时,显示注销、用户名、用户等级;
当未登录成功时,显示登录图标。
5.1.导入依赖
<!--security-thymeleaf整合包-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
5.2. 首页命名空间
<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
5.3.
<!--如果未登录:显示登录图标-->
<div sec:authorize="!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="name"></span>
</a>
</div>
<div sec:authorize="isAuthenticated()">
<a class="item" th:href="@{/logout}">
<i class="sign-out icon"></i> 注销
</a>
</div>
5.4.
<div class="column" sec:authorize="hasRole('vip1')">//认证为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>
功能实现:记住我及首页定制
1.首页定制
先将默认/login路径转为/toLogin路径,使登录页面显示自己定制的漂亮页面
1.1.
在首页页面修改跳转路径
<div sec:authorize="!isAuthenticated()">
<a class="item" th:href="@{/toLogin}">
<i class="address card icon"></i> 登录
</a>
</div>
在控制器处修改路径
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
在登录页面修改提交数据路径
<form th:action="@{/login}" method="post">
但是此处一定想以/login,为提交数据路径时,可在securityConfig中进行一下设置
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");
接下去看源码formLogin里面的,发现还有两个方法
* .usernameParameter("username") // default is username
* .passwordParameter("password") // default is password
也就是说在login.html里面,如果name改成了别的,就可以在此处设置例:
<input type="text" placeholder="Username" name="user">
<input type="password" name="pwd">
http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");
- 记住功能设置
在登录页面加上
<div class="field">
<input type="checkbox" name="remember"> 记住我
</div>
在securityConfig中
//开启记住我功能 cookie,默认保存两周,自定义接收前端的参数
http.rememberMe().rememberMeParameter("remember");
– 资料部分选自狂神说JAVA