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,进行回答: 黑客登录系统使用的密码是_____________。 题目思路: 分析题目&…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
