Spring Boot开发Spring Security
这里我对springboot不做过多描述,因为我觉得学这个的肯定掌握了springboot这些基础
导入核心依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring‐boot‐starter‐security</artifactId>
</dependency>
Servlet Context配置
@Configuration
public class WebConfig implements WebMvcConfigurer {//默认Url根路径跳转到/login,此url为spring security提供@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("redirect:/login");}
}
Spring Security为我们提供了登录页面,这里我是将 "/",路径设置为登陆页面的路径,方便测试,
也可以自定义登录页面,我会在后面说明
application.properties配置文件
server.port=8080
server.servlet.context-path=/security-springboot
spring.application.name = security-springbootspring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jspspring.datasource.url=jdbc:mysql://localhost:3306/user_db
spring.datasource.username=root
spring.datasource.password=XXXX
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
至于为什么不是yml,这完全不是这里的重点,关于前端用的jsp,各位看官姥爷们也凑合看吧,理解这个框架就好,最下面的数据库配置这里也可以先不做,后面也会详细说明
核心配置来喽,WebSecurityConfig
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {//定义用户信息服务(查询用户信息)
/*@Beanpublic UserDetailsService userDetailsService(){InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());return manager;}
*///密码编码器@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//安全拦截机制(最重要)@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests()
// .antMatchers("/r/r1").hasAuthority("p2")
// .antMatchers("/r/r2").hasAuthority("p2").antMatchers("/r/**").authenticated()//所有/r/**的请求必须认证通过.anyRequest().permitAll()//除了/r/**,其它的请求可以访问.and().formLogin()//允许表单登录.loginPage("/login-view")//登录页面.loginProcessingUrl("/login").successForwardUrl("/login-success")//自定义登录成功的页面地址.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().logout().logoutUrl("/logout").logoutSuccessUrl("/login-view?logout");}
}
如果不想连接数据库测试,这里可以先把这些注释解除掉去掉,用模拟数据
controller代码
@RestController
public class LoginController {@RequestMapping(value = "/login-success",produces = {"text/plain;charset=UTF-8"})public String loginSuccess(){//提示具体用户名称登录成功return getUsername()+" 登录成功";}/*** 测试资源1* @return*/@GetMapping(value = "/r/r1",produces = {"text/plain;charset=UTF-8"})public String r1(){return "访问资源1";}/*** 测试资源2* @return*/@GetMapping(value = "/r/r2",produces = {"text/plain;charset=UTF-8"})public String r2(){return " 访问资源2";}}
工作原理
认证流程

AuthenticationProvider
public interface AuthenticationProvider {Authentication authenticate(Authentication authentication) throws AuthenticationException;boolean supports(Class<?> var1);
} public boolean supports(Class<?> authentication) {return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
} public interface Authentication extends Principal, Serializable {Collection<? extends GrantedAuthority> getAuthorities();Object getCredentials();Object getDetails();Object getPrincipal();boolean isAuthenticated();void setAuthenticated(boolean var1) throws IllegalArgumentException;
} UserDetailsService
public interface UserDetails extends Serializable {Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled();
} PasswordEncoder
public interface PasswordEncoder {String encode(CharSequence var1);boolean matches(CharSequence var1, String var2);default boolean upgradeEncoding(String encodedPassword) {return false;}
} @Bean
public PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();
} 授权流程


(不过后面我们都会从数据库中拿)
授权决策

自定义认证
自定义登录页面

@Configuration//就相当于springmvc.xml文件
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("redirect:/login-view");registry.addViewController("/login-view").setViewName("login");}} //配置安全拦截机制
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/r/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin() (1)
.loginPage("/login‐view") (2)
.loginProcessingUrl("/login") (3)
.successForwardUrl("/login‐success") (4)
.permitAll();
} 问题解决
@Override
protected void configure(HttpSecurity http) throws Exception {http.csrf().disable() //屏蔽CSRF控制,即spring security不再限制CSRF...
} 连接数据库认证
创建数据库
CREATE DATABASE `user_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE TABLE `t_user` (`id` bigint(20) NOT NULL COMMENT '用户id',`username` varchar(64) NOT NULL,`password` varchar(64) NOT NULL,`fullname` varchar(255) NOT NULL COMMENT '用户姓名',`mobile` varchar(11) DEFAULT NULL COMMENT '手机号',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC application.properties配置
spring.datasource.url=jdbc:mysql://localhost:3306/user_db
spring.datasource.username=root
spring.datasource.password=mysql
spring.datasource.driver‐class‐name=com.mysql.jdbc.Driver <dependency><groupId>org.springframework.boot</groupId><artifactId>spring‐boot‐starter‐jdbc</artifactId>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql‐connector‐java</artifactId><version>5.1.47</version>
</dependency> pom.xml添加依赖,mysql版本根据自己情况
定义模型类型,在model包定义UserDto
@Data
public class UserDto {private String id;private String username;private String password;private String fullname;private String mobile;
}
在Dao包定义UserDao:
@Repository
public class UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
public UserDto getUserByUsername(String username){
String sql ="select id,username,password,fullname from t_user where username = ?";
List<UserDto> list = jdbcTemplate.query(sql, new Object[]{username}, new
BeanPropertyRowMapper<>(UserDto.class));
if(list == null && list.size() <= 0){
return null;
}
return list.get(0);
}
} 定义UserDetailService
@Service
public class SpringDataUserDetailsService implements UserDetailsService {
@Autowired
UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//登录账号
System.out.println("username="+username);
//根据账号去数据库查询...
UserDto user = userDao.getUserByUsername(username);
if(user == null){
return null;
}
//这里暂时使用静态数据
UserDetails userDetails =
User.withUsername(user.getFullname()).password(user.getPassword()).authorities("p1").build();
return userDetails;
}
} 使用BCryptPasswordEncoder
WebSecurityConfig中
@Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
}
会话
获取用户身份
@RestController
public class LoginController {@RequestMapping(value = "/login-success",produces = {"text/plain;charset=UTF-8"})public String loginSuccess(){//提示具体用户名称登录成功return getUsername()+" 登录成功";}/*** 测试资源1* @return*/@GetMapping(value = "/r/r1",produces = {"text/plain;charset=UTF-8"})public String r1(){return getUsername()+" 访问资源1";}/*** 测试资源2* @return*/@GetMapping(value = "/r/r2",produces = {"text/plain;charset=UTF-8"})public String r2(){return getUsername()+" 访问资源2";}//获取当前用户信息private String getUsername(){String username = null;//当前认证通过的用户身份Authentication authentication = SecurityContextHolder.getContext().getAuthentication();//用户身份Object principal = authentication.getPrincipal();if(principal == null){username = "匿名";}if(principal instanceof org.springframework.security.core.userdetails.UserDetails){UserDetails userDetails = (UserDetails) principal;username = userDetails.getUsername();}else{username = principal.toString();}return username;}
} 会话控制
@Override
protected void configure(HttpSecurity http) throws Exception {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
} 会话超时
server.servlet.session.timeout = 3600s
http.sessionManagement().expiredUrl("/login‐view?error=EXPIRED_SESSION").invalidSessionUrl("/login‐view?error=INVALID_SESSION"); 安全会话cookie
server.servlet.session.cookie.http‐only = trueserver.servlet.session.cookie.secure = true
退出
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/login‐view?logout"); @Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
//...
.and()
.logout() (1)
.logoutUrl("/logout") (2)
.logoutSuccessUrl("/login‐view?logout") (3)
.logoutSuccessHandler(logoutSuccessHandler) (4)
.addLogoutHandler(logoutHandler) (5)
.invalidateHttpSession(true); (6)
} 相关文章:
Spring Boot开发Spring Security
这里我对springboot不做过多描述,因为我觉得学这个的肯定掌握了springboot这些基础 导入核心依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring‐boot‐starter‐security</artifactId> </depen…...
gin介绍及helloworld
1. 介绍 Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点 对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单&…...
vue3 自动引入 ref reactive...
npm i unplugin-auto-import -D vite.config.js import { defineConfig } from vite; import vue from vitejs/plugin-vue; import AutoImport from unplugin-auto-import/vite;export default defineConfig({plugins: [vue(),AutoImport({// 自动导入 Vue 相关函数࿰…...
软考复习之软件工程篇
软件生命周期 问题定义:要示系统分析员与用户进行交流,弄清”用户需要计算机解决什么问题”然后提出关于“系统目标与范围的说明”,提交用户审查和确认 可行性研究:一方面在于把待开发的系统的目标以明确的语言描述出来…...
MySQL(七)MySQL和Oracle、PostgreSQL的区别
文章目录 一、MySQL和Oracle1.1 基本差别1.2 使用区别 二、MySQL和PostgreSQL2.1 基本差别2.2 使用差别 本系列文章: MySQL(一)SQL语法、数据类型、常用函数、事务 MySQL(二)MySQL SQL练习题 MySQL(三&…...
(2)(2.4) CRSF/ELRS Telemetry
文章目录 前言 1 ArduPilot 参数编辑器 前言 !Note ELRS(ExpressLRS)遥控系统使用穿越火线协议,连接方式类似。不过,它不像穿越火线那样提供双向遥测。 TBS CRSF 接收机与 ArduPilot 的接口中包含遥测和遥控信息。…...
服务器发送http请求
1、发送GET请求 curl localhost:9009/setCreateDataItem?a1&bnihao 2、发送POST请求 curl -X POST -d a1&bnihao localhost:9009/setCreateDataItem 3、发送json格式请求: curl -H "Content-Type: application/json" -X POST -d {"abc…...
Effective Objective-C 学习第二周
理解“属性”这一概念 “属性”(property)是 Objective-C 的一项特性,用于封装对象中的数据。Objective-C 对象通常会把其所需的数据保存为各种实例变量。实例变量一般通过“存取方法”来访问。其中,“获取方法”(get…...
JS进阶-深入对象(二)
拓展:深入对象主要介绍的是Js的构造函数,实例成员,静态成员,其中构造函数和Java种的构造函数用法相似,思想是一样的,但静态成员和实例成员和java种的有比较大的差别,需要认真理解 • 创建对象三…...
【Gene Expression Prediction】Part2 Enchancer discovery
文章目录 5. 第一个讲座:Enchancer discovery5.1 STARR-seq5.2 Enchancer detection with weakly supervised learning5.3 Model performance 来自Manolis Kellis教授(MIT计算生物学主任)的课 YouTube:(Gene Expression Predictio…...
【UEFI基础】EDK网络框架(UDP4)
UDP4 UDP4协议说明 UDP的全称是User Datagram Protocol,它不提供复杂的控制机制,仅利用IP提供面向无连接的通信服务。它将上层应用程序发来的数据在收到的那一刻,立即按照原样发送到网络。 UDP报文格式: 各个参数说明如下&…...
vivado使用注意事项
记得给constrs(.xdc)限制文件设置为目标文件(set as Target Consraint File)...
gin路由篇
1. 基本路由 gin 框架中采用的路由库是基于httprouter做的 import ("net/http""github.com/gin-gonic/gin" )func main() {// 1.创建路由r : gin.Default()// 2.绑定路由规则,执行的函数// gin.Context,封装了request和responser.…...
C++逆向分析--继承的本质
一.一些思考 继承是面向对象的三个特性之一。这篇文章我们从底层的角度去理解什么是继承。他的作用是什么。首先继承的出现是更好的避免代码的重复冗余。要理解一件事很重要,C其实是C的延申。那么C的出现是为了解决C语言上C祖师爷认为不友好的事情,也为…...
LeetCode解法汇总2865. 美丽塔 I
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 描述: 给你一个长…...
pinia 的使用方法
使用方式(选项式) 1、在 mian.js 导入 pinia 里的 createPinia 函数。 2、app.use 这个 createPinia 函数的返回值。 // main.jsimport { createPinia } from pinia;app.use(createPinia()); 3、创建一个 js 文件(该文件保存着共享的数据&…...
sky_take_out
day01: 前端网址通过nginx访问后端网址(前后网址不一致),有三个好处: 一是提高访问速度,二是进行负载均衡,三是保障后端安全性 用md5加密了密码 后端使用knife4j调试,用Swagger生成接口文档&am…...
LC 2865. 美丽塔 I
2865. 美丽塔 I 难度 : 中等 题目大意 给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。 你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。 如果以下条件满足,我们称这些塔是 美丽 的: 1 < heights…...
代理设计模式JDK动态代理CGLIB动态代理原理
代理设计模式 代理模式(Proxy),为其它对象提供一种代理以控制对这个对象的访问。如下图 从上面的类图可以看出,通过代理模式,客户端访问接口时的实例实际上是Proxy对象,Proxy对象持有RealSubject的引用&am…...
[陇剑杯 2021]webshell
[陇剑杯 2021]webshell 题目做法及思路解析(个人分享) 问一:单位网站被黑客挂马,请您从流量中分析出webshell,进行回答: 黑客登录系统使用的密码是_____________。 题目思路: 分析题目&…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
