Security
SpringSecurity(安全)
在web开发者,安全第一位!过滤器,拦截器!
shiro,SpringSecurity 认证,授权
- 功能权限
- 访问权限
- 菜单权限
简介
SpringSecurity是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,它可以实现强大的web安全控制,对于安全控制,我们仅需引入spring-boot-starter-security模块,进行少量的配置。
核心类:
- WebSecuriyConfigurerAdapter:自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式
Spring Security两个目标,认证(Authentication)和授权(Authorization)
官网:https://spring.io/projects/spring-security/
官方文档:https://docs.spring.io/spring-security/site/docs/5.4.5/reference/html5/
Spring Security环境搭建
依赖
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
<!--thymeleaf security整合包-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Controller
@Controller
public class RouterController {
@RequestMapping({"/", "/index"})
public String index() {
return "index";
}
@RequestMapping({"/toLogin"})
public String toLogin() {
return "views/login";
}
@RequestMapping({"/level1/{id}"})
public String toLevel1(@PathVariable("id") int id) {
return "views/level1/" + id;
}
@RequestMapping({"/level2/{id}"})
public String toLevel2(@PathVariable("id") int id) {
return "views/level2/" + id;
}
@RequestMapping({"/level3/{id}"})
public String toLevel3(@PathVariable("id") int id) {
return "views/level3/" + id;
}
}
Security配置类
//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");
//没有权限会到登陆页面
http.formLogin();
//开启注销功能,注销成功到主页,此处也可以做删除cookies和session操作
http.logout().logoutSuccessUrl("/");
}
//认证,Springboot 2.1.x之后版本会报错,密码没有编码There is no PasswordEncoder
//密码编码:PasswordEncoder
//spring security5.0有很多加密方法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/* auth.inMemoryAuthentication()
.withUser("jpy").password("123456").roles("vip2", "vip3")
.and()
.withUser("admin").password("123456").roles("vip1", "vip2", "vip3")
.and()
.withUser("guest").password("123456").roles("vip1");*/
//从内存中,也可以从数据库jdbc
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("jpy").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2", "vip3")
.and()
.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2", "vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
前端
此时用户名显示不出来,是因为springboot版本过高,只有2.1.x之前才支持
<div class="ui segment" id="index-header-nav" th:fragment="nav-menu">
<div class="ui secondary menu">
<a class="item" th:href="@{/index}">首页</a>
<!--登录注销-->
<div class="right menu">
<!--如果未登录,显示登陆按钮-->
<!--未登录-->
<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>
</div>
</div>
</div>
改变springboot依赖为2.0.9,可以显示用户名,但注销时会报404错误。注销通过get请求,不安全,所以报错,通过配置类以下配置,关闭放攻击。
//关闭防攻击
http.csrf().disable();
根据用户动态显示菜单
通过标签sec:authorize="hasRole('vip1')"
<div class="ui three column stackable grid">
<!--根据用户动态显示菜单-->
<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>
</div>
开启记住我功能
//记住我,cookies实现,默认保存两周
http.rememberMe();
定制登陆页,自定义记住我
<div class="ui placeholder segment">
<div class="ui column very relaxed stackable grid">
<div class="column">
<div class="ui form">
<!--1.login-->
<form th:action="@{/login}" method="post">
<div class="field">
<label>Username</label>
<div class="ui left icon input">
<input type="text" placeholder="Username" name="user">
<i class="user icon"></i>
</div>
</div>
<div class="field">
<label>Password</label>
<div class="ui left icon input">
<input type="password" name="pwd">
<i class="lock icon"></i>
</div>
</div>
<div class="field">
<input type="checkbox" name="remember">记住我
</div>
<input type="submit" class="ui blue submit button"/>
</form>
</div>
</div>
</div>
</div>
自定义loginPage为toLogin时如果login.html中form表单提交路径和自定义的toLogin不一样,就必须手手动配置把登陆页面路径配置到loginProcessingUrl("/login")
登陆页面表单用户名不是username和password,就必须吧表单中参数配置进usernameParameter和passwordParameter
http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");
自定义记住我,rememberMeParameter中参数必须和登陆页面自己写的记住我input框的name一样
http.rememberMe().rememberMeParameter("remember");
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY