Java之SpringSecurity使用心得

news2025/2/24 14:23:52

在这里插入图片描述

文章目录

  • 一、内存身份认证
  • 二、jdbc身份认证
  • 三、自定义登录页

一、内存身份认证

添加pom依赖

<!-- Spring Security提供的安全管理依赖启动器 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

身份认证核心代码

@EnableWebSecurity
public class SecurityConfigMemory {

    @Bean
    public static PasswordEncoder passwordEncoder(){
        // 或者Pbkdf2PasswordEncoder、ScryptPasswordEncoder
        return new BCryptPasswordEncoder();
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception{
        httpSecurity.csrf().disable()
        .authorizeHttpRequests((authorize) ->{
            authorize.anyRequest().authenticated();
        })
        .httpBasic(Customizer.withDefaults());
        return httpSecurity.build();
    }

    /**
     * 内存身份认证
     * @return
     */
    @Bean
    public UserDetailsService userDetailsService(){
        UserDetails tom = User.builder()
            .username("tom")
            .password(passwordEncoder().encode("111222"))
            // 角色
            .roles("common","vip")
            .build();

        UserDetails jerry = User.builder()
            .username("jerry")
            .password(passwordEncoder().encode("111222"))
            // 权限
            .authorities("ROLE_vip")
            .build();
        return new InMemoryUserDetailsManager(tom,jerry);
    }

}

实际效果
在这里插入图片描述

二、jdbc身份认证

就是把用户密码数据存到数据库里,不用直接放代码里,每次修改都是重新部署
需要到org.springframework.security.core.userdetails.jdbc.users.ddl中复制出创建sql脚本,创建两张表,首次运行服务后自动插入数据。
在这里插入图片描述

具体sql如下:users.ddl

create table users(username varchar_ignorecase(50) not null primary key,password varchar_ignorecase(500) not null,enabled boolean not null);
create table authorities (username varchar_ignorecase(50) not null,authority varchar_ignorecase(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);

核心代码

<!-- JDBC数据库连接启动器 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
@EnableWebSecurity
public class SecurityConfigDb {

    @Autowired
    private DataSource dataSource;

    @Bean
    public static PasswordEncoder passwordEncoder() {
        // 或者Pbkdf2PasswordEncoder、ScryptPasswordEncoder
        return new BCryptPasswordEncoder();
    }

    // 用户授权管理自定义配置,用户名密码弹框登录,放行静态资源
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
        .authorizeHttpRequests((authorize) -> {
            authorize
            .anyRequest().authenticated();
        })
        .httpBasic(Customizer.withDefaults())
        .csrf().disable();
        return httpSecurity.build();
    }

    /**
     * jdbc身份认证
     * 首次登录成功后,第二次重启服务后可以无须登录直接访问,应该是把登录结果存到浏览器缓存或token里了,重新打开浏览器即需要重新登录
     * @return
     */
    @Bean
    public UserDetailsService userDetailsService() {
        return new JdbcUserDetailsManager(dataSource);
    }

}

实际效果同第一个
在上面代码的userDetailService方法中,也可以通过代码添加用户密码

@Bean
public UserDetailsService userDetailsService() {
    JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
    if (!manager.userExists("ddd")) {
        manager.createUser(User.withUsername("ddd").password(passwordEncoder().encode("123123")).roles("common", "vip").build());
    }
    if (!manager.userExists("jerry")) {
        manager.createUser(User.withUsername("jerry").password(passwordEncoder().encode("111222")).authorities("ROLE_vip").build());
    }
    return manager;
}

三、自定义登录页

1,pom依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2,修改properties配置

#prefix中后边的斜杠不能少
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html

3,新建login.html

<!DOCTYPE html>
<html lang="zh-cn" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Login Page</title>
    <link th:href="@{/css/login.css}" href="/css/login.css"  th:rel="stylesheet"/>
  </head>
  <body>
    <div class="login-container">
      <h2>登录页面</h2>
      <form th:action="@{/doLogin}" method="post">
        <div th:class="form-group"><label> 用户名 : <input type="text" name="username" required/> </label></div>
        <div th:class="form-group"><label> 密 码: <input type="password" name="password" required/> </label></div>
        <div th:class="form-group"><input type="submit" value="登 录"/></div>
      </form>
    </div>
  </body>
</html>

关联的样式login.css

body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}
.login-container {
  background-color: #fff;
  padding: 20px;
  border-radius: 5px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.form-group {
  margin-bottom: 15px;
}
.form-group label {
  display: block;
  margin-bottom: 5px;
}
.form-group input {
  width: 100%;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
  box-sizing: border-box; /* ensures padding doesn't affect width */
}
.form-group input[type="submit"] {
  background-color: #5c79b8;
  color: white;
  cursor: pointer;
}
.form-group input[type="submit"]:hover {
  background-color: #4cae97;
}
.h2{
  width: 100%;
}

4,新建Controller

@Controller
public class IndexController {

    @RequestMapping("/entry")
    public String index(){
        System.out.println("访问登录页面");
        return "login";
    }

    @RequestMapping("/entry-success")
    public String success(){
        System.out.println("访问登录success页面");
        // return "登录成功";
        return "success";
    }

    @RequestMapping("/entry-failure")
    public String failure(){
        System.out.println("访问登录failure页面");
        // return "登录失败";
        return "failure";
    }
}
@Slf4j
@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/test")
    public String test() {
        return "this is ngrok info test for xmliu";
    }
}

5,Security配置优化:添加放行css文件,登录页接口,登录成功和登录失败以及登录提交表单方法
在第二个配置的基础上修改securityFilterChain方法

// 用户授权管理自定义配置,用户名密码弹框登录,放行静态资源
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
    .authorizeHttpRequests((authorize) -> {
        authorize
        .antMatchers("/css/**","/img/**").permitAll()
        .anyRequest().authenticated();
    })
    .httpBasic(Customizer.withDefaults())
    // .authorizeRequests().antMatchers("/css/**").permitAll().anyRequest().authenticated().and()
    // 开启基于表单的用户登录
    .formLogin()
    // 自定义登录页面接口
    .loginPage("/entry")
    // 用户名参数,默认username,如果表单中用户名参数是username可以忽略此项
    .usernameParameter("username")
    // 用户名参数,默认password,如果表单中密码参数是password可以忽略此项
    .passwordParameter("password")
    // 登录表单提交按钮处理方法
    .loginProcessingUrl("/doLogin")
    // 登录成功后跳转到首页index.html
    .defaultSuccessUrl("/")
    // 登录失败跳转到失败页的接口
    .failureUrl("/entry-failure")
    // 允许放行,spring security不会对这个端点做授权检查
    .permitAll()
    .and().csrf().disable();
    return httpSecurity.build();
}

6,resources目录结构如下图
在这里插入图片描述

除了login.html,其他几个html文件都差不多,就是文字不一样而已,这里以index.html为例

<!DOCTYPE html>
<html lang="zh-cn" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Login Page</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        background-color: #f4f4f4;
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
      }
    </style>
  </head>
  <body>
    <div>
      <h2>首页</h2>
    </div>
  </body>
</html>

7,由于项目中我添加了拦截器,所以关于资源放行这块,还需要在拦截器中做处理

@Configuration
@Component
public class MyInterceptor implements HandlerInterceptor {

    @Resource
    MyComp myComp;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 获取接口地址
        String url = request.getRequestURL().toString();
        ...
        // 添加判断,防止css文件访问不了报错
        if(url.endsWith("/xmliu/") || url.endsWith("css")){
            return true;
        }
            ...
        return false
    }

拦截器配置

@Configuration
public class MyWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry
        .addInterceptor(interceptor())
        // 不拦截哪些请求
        .excludePathPatterns("/city/**")
        // 不拦截自定义的spring security登录页面
        .excludePathPatterns("/error")
        .excludePathPatterns("/entry")
        .excludePathPatterns("/entry-failure")
        .excludePathPatterns("/entry-success")
        .excludePathPatterns("/api/**");
    }

    /**
     * @return myInterceptor
     */
    @Bean
    public MyInterceptor interceptor() {
        return  new MyInterceptor();
    }
}

8,实际效果
在这里插入图片描述

用户名和密码输入错误
在这里插入图片描述

输入正确登录成功,进入首页
在这里插入图片描述

如果刚开始就是访问的接口页,那么登录成功后页会直接访问接口,而不是进入首页

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1691233.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

串口服务器在工业控制领域的应用:深度解析与前沿实践

在工业控制领域&#xff0c;随着技术的不断发展&#xff0c;传统的串口通信方式已经难以满足现代工业系统对高效、稳定、安全通信的需求。此时&#xff0c;串口服务器作为一种先进的通信技术解决方案&#xff0c;正在逐步改变工业控制领域的通信格局。本文将深度解析串口服务器…

第十届水利、土木工程国际学术会议暨工程安全与防灾论坛 (ICHCE ESDP 2024)

文章目录 一、会议详情二、重要信息三、会议简介四、组织单位五、出席嘉宾六、大会议程七、咨询 一、会议详情 二、重要信息 会议官网&#xff1a;www.ichce.org 大会时间&#xff1a;2024年8月9-11日 最后一轮截稿时间&#xff1a;2024年6月30日 报名截止时间&#xff1a;2…

得物小程序逆向+qt可视化(不含sku)

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

linux-配置服务器之间 ssh免密登录

前言 在管理多台Linux服务器时,为了方便操作和自动化任务,实现服务器之间的SSH免密登录是非常有必要的。SSH免密登录可以避免每次远程连接时输入密码,大大提高效率。本文将详细介绍SSH免密登录的原理和实现步骤。 一、原理解释 SSH免密登录的实现依赖于SSH密钥对,主要是利用…

为什么手机冬天续航短 – 锂电池的温度特性曲线

原文出自微信公众号【小小的电子之路】 相信大家都有这样的经历&#xff1a;手机的续航能力在寒冷的冬天会有一定程度的降低&#xff0c;有些手机甚至充不进去电。在这种情况下&#xff0c;有些人可能会在手机上贴一个暖宝宝。其实这个问题不止出现在手机上&#xff0c;大家如果…

Mybatis Cache(一)MybatisCache+Redis

前面提到了&#xff0c;使用mybatis cache&#xff0c;一般是结合redis使用。 一、demo 1、数据表 create table demo.t_address (id int auto_incrementprimary key,address_name varchar(200) null,address_code varchar(20) null,address_type int n…

Java进阶学习笔记4——Static应用知识:代码块

代码块&#xff1a; 代码块是类的五大成员之一&#xff08;成员变量、构造器、方法、代码块、内部类&#xff09;。 Java类生命周期&#xff1a;加载、验证、准备、初始化、卸载。 代码块分为两种&#xff1a; 静态代码块&#xff1a; 格式&#xff1a;static {} 特点&…

Linux--网络通信(一)概述

网络通信概述 网络通信本质上是一种进程间通信&#xff0c;是位于网络中不同主机上的进程之间的通信&#xff0c;属于 IPC 的一种&#xff0c; 通常称为 socket IPC。所以网络通信是为了解决在网络环境中&#xff0c;不同主机上的应用程序之间的通信问题。 大概可以分为三个层…

物联网应用开发--STM32与机智云通信(ESP8266 Wi-Fi+手机APP+LED+蜂鸣器+SHT20温湿度传感器)

实现目标 1、熟悉机智云平台&#xff0c;会下载APP 2、熟悉新云平台创建产品&#xff0c;项目虚拟调试 3、掌握云平台生成MCU代码&#xff0c;并移植。机智云透传固件的下载 4、具体目标&#xff1a;&#xff08;1&#xff09;注册机智云平台&#xff1b;&#xff08;2&…

转行3年涨薪300%,我总结了一套产品经理快速入门指南!

想转行的产品小白&#xff0c;初期一定会遇到这个问题——我要如何 0 基础转行产品经理&#xff1f; 要想 0 基础快速转行产品经理&#xff0c;我通过个人实践总结了 5 个关键点&#xff0c;可以参考。 一、熟悉产品经理的工作全流程 转行的产品小白&#xff0c;首先要建立产…

mninst数据集图片下载

//不需要在官网下载&#xff0c;直接通过python代码&#xff0c;利用pytorch下载即可 from icecream import ic from torchvision import datasets from tqdm import tqdm import ostrain_data datasets.MNIST(root"./data/", trainTrue, downloadTrue) test_data …

VMware虚拟机桥接无线网卡上网(WIFI)

一、打开VM点击【编辑】-【虚拟网络编辑器】 二、点击【桥接模式】- 点击【自动设置】- 选择自己的无线网适配器 - 【确定】 三、开机之后会弹出提示连接网络&#xff0c;就能看见网络已经连上了

FastCopy

目录 背景: 简介&#xff1a; 原理: 下载地址: 工具的使用: 背景: 简介&#xff1a; FastCopy是一款速度非常快的拷贝软件&#xff0c;软件版本为5.7.1 Fastcopy是日本的最快的文件拷贝工具&#xff0c;磁盘间相互拷贝文件是司空见惯的事情&#xff0c;通常情况…

零一万物Yi-1.5开源,34B/9B/6B多尺寸,34B超Qwen1.5-72B

前言 近年来&#xff0c;大型语言模型&#xff08;LLM&#xff09;在各个领域展现出惊人的能力&#xff0c;为人们的生活和工作带来了巨大的改变。然而&#xff0c;大多数开源 LLM 的性能仍然无法与闭源模型相媲美&#xff0c;这限制了 LLM 在科研和商业领域的进一步应用。为了…

C# 利用Xejen框架源码,我们来开发一个基于Dapper技术的数据库通用的帮助访问类,通过Dapper的增删改查,可以访问Sqlite数据库

Dapper 是一个轻量级的对象关系映射&#xff08;ORM&#xff09;工具&#xff0c;适用于 .NET 平台。它由 Stack Overflow 团队开发&#xff0c;旨在提供简单、高效的数据访问功能。与其他重量级 ORM&#xff08;如 Entity Framework&#xff09;相比&#xff0c;Dapper 更加轻…

【算法例题】n元钱买n只鸡

题目描述&#xff1a;公鸡5元1只&#xff0c;母鸡3元1只&#xff0c;小鸡1元3只&#xff0c;问&#xff1a;n元钱买n只鸡&#xff0c;怎么买&#xff1f; 解题思路&#xff1a;这题要用枚举算法&#xff0c;枚举鸡的数量&#xff0c;代码如下&#xff1a; ​#include <bit…

博客系统(Servlet实现)

目录 1.准备工作 2.数据库设计 2.1表设计 2.2封装数据库操作代码 2.3创建 Blog 类 和 User 类 2.4创建 BlogDao 类和 UserDao 类 3.读取博客列表功能 3.1约定前后端交互接口 3.2实现服务器代码 3.3实现客户端代码 4.实现博客详情 4.1约定前后端交互接口 4.2实现服…

jmeter之线程组教程

一、线程组的作用 线程组是测试计划的子控件&#xff0c;也是取样器的父控件setup线程组&#xff0c;在所有线程组之前运行&#xff0c;类似于unittest框架中的SetUp函数&#xff0c;初始化环境teardown线程组&#xff0c;在所有线程组之后运行&#xff0c;类似于unittest中的…

如何在Windows 11和10上检查计算机的正常运行时间,这里有两种方法

序言 你的计算机的正常运行时间告诉你打开计算机已经有多长时间了。如果你需要这些信息进行故障排除或其他操作&#xff0c;那么很容易在Windows 11和Windows 10操作系统上找到你的正常运行时间。我们将向你展示图形和命令行方法。让我们开始吧。 使用任务管理器查找Windows正…

YoloV9实战与改进——专栏目录

摘要 &#x1f525;&#x1f680;本专栏教你如何嗨翻Yolov9&#xff01;&#x1f680;&#x1f525; &#x1f680;炸裂升级&#xff1a;嗨&#xff0c;小伙伴们&#xff01;这里有一波Yolov9的升级大招&#xff0c;带你领略最新论文的精华&#xff01;&#x1f4a5; 什么注意…