从零开始学Spring Boot系列-集成Spring Security实现用户认证与授权

spring,boot,security · 浏览次数 : 0

小编点评

本文将指导如何在Spring Boot项目中集成Spring Security,实现用户认证与授权。首先,我们创建了一个Spring Boot项目并添加了相关依赖。接着,我们创建了实体类、Mapper接口、Service接口和实现类、UserDetailsService实现类、Java配置类等组件。最后,我们创建了登录页面和控制器,实现了用户登录功能。 1. 创建Spring Boot项目并添加依赖 在IDE(如IntelliJ IDEA或Eclipse)中创建一个新的Spring Boot项目,选择所需的依赖,如Web、Thymeleaf、Spring Security等。在pom.xml(Maven)或build.gradle(Gradle)文件中添加Spring Security和MyBatis-Plus的依赖。 2. 创建实体类 创建一个简单的实体类User,用于映射数据库表。使用Lombok库简化实体类的创建过程。 3. 创建Mapper接口 创建一个UserMapper接口,继承BaseMapper,用于执行数据库操作。 4. 创建Mapper XML文件 在resources/mapper目录下创建UserMapper.xml文件,定义SQL查询和结果映射。 5. 创建Service接口和实现类 创建UserService接口和UserServiceImpl实现类,实现用户服务和用户认证逻辑。 6. 创建UserDetailsService实现类 创建UserDetailServiceImpl实现类,实现UserDetailsService接口,用于加载用户详细信息。 7. 创建Java配置类 创建SecurityConfig类,配置Spring Security和密码编码器。 8. 创建登录页面 在src/main/resources/templates目录下创建login.html文件,实现用户登录界面。 9. 创建控制器 创建UserController类,处理用户登录请求,并调用Service层进行认证。 通过以上步骤,我们成功地在Spring Boot项目中集成了Spring Security,实现了用户认证与授权。在实际应用中,还需要根据具体需求进行配置和优化。

正文

在Web应用程序中,安全性是一个至关重要的方面。Spring Security是Spring框架的一个子项目,用于提供安全访问控制的功能。通过集成Spring Security,我们可以轻松实现用户认证、授权、加密、会话管理等安全功能。本篇文章将指导大家从零开始,在Spring Boot项目中集成Spring Security,并通过MyBatis-Plus从数据库中获取用户信息,实现用户认证与授权。

环境准备

在开始之前,请确保你的开发环境已经安装了Java、Gradle和IDE(如IntelliJ IDEA或Eclipse)。同时,你也需要在项目中引入Spring Boot、Spring Security、MyBatis-Plus以及数据库的依赖。

创建Spring Boot项目

首先,我们需要创建一个Spring Boot项目。可以使用Spring Initializr(https://start.spring.io/)来快速生成项目结构。在生成项目时,选择所需的依赖,如Web、Thymeleaf(或JSP)、Spring Security等。

添加Spring Security依赖

在项目的pom.xml(Maven)或build.gradle(Gradle)文件中,添加Spring Security的依赖。
对于Gradle,添加以下依赖:

group = 'cn.daimajiangxin'
version = '0.0.1-SNAPSHOT'
description ='Spring Security'
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    runtimeOnly 'mysql:mysql-connector-java:8.0.17'
    // MyBatis-Plus 依赖
    implementation 'com.baomidou:mybatis-plus-spring-boot3-starter:3.5.5'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}

对于Maven,添加以下依赖:

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

创建实体类

创建一个简单的实体类,映射到数据库表。

package cn.daimajiangxin.springboot.learning.model;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

@TableName(value ="user")
@Data
public class User implements Serializable {
    /**
     * 学生ID
     */
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 姓名
     */
    private String name;
    @TableField(value="user_name")
    private String userName;

    private String password;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 备注
     */
    private String remark;



    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

创建Mapper接口

创建对应的Mapper接口,通常放在与实体类相同的包下,并继承BaseMapper 接口。例如:

package cn.daimajiangxin.springboot.learning.mapper;

import cn.daimajiangxin.springboot.learning.model.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {

}

创建Mapper XML文件

在resources的mapper目录下创建对应的XML文件,例如UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.daimajiangxin.springboot.learning.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="cn.daimajiangxin.springboot.learning.model.User">
            <id property="id" column="id" jdbcType="BIGINT"/>
            <result property="name" column="name" jdbcType="VARCHAR"/>
            <result property="user_name" column="userName" jdbcType="VARCHAR"/>
            <result property="password" column="password" jdbcType="VARCHAR"/>
            <result property="email" column="email" jdbcType="VARCHAR"/>
            <result property="age" column="age" jdbcType="INTEGER"/>
            <result property="remark" column="remark" jdbcType="VARCHAR"/>
    </resultMap>

    <sql id="Base_Column_List">
        id,name,email,age,remark
    </sql>
  
    <select id="findAllUsers"  resultMap="BaseResultMap">
     select
       <include refid="Base_Column_List"></include>
     from user
    </select>
</mapper>

创建Service 接口

在service目录下服务类接口UserService

package cn.daimajiangxin.springboot.learning.service;

import cn.daimajiangxin.springboot.learning.model.User;
import com.baomidou.mybatisplus.extension.service.IService;

public interface UserService extends IService<User> {

}

创建Service实现类

在service目录下创建一个impl目录,并创建UserService实现类UserServiceImpl

package cn.daimajiangxin.springboot.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.daimajiangxin.springboot.learning.model.User;
import cn.daimajiangxin.springboot.learning.service.UserService;
import cn.daimajiangxin.springboot.learning.mapper.UserMapper;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{

}

创建UserDetailsService实现类

package cn.daimajiangxin.springboot.learning.service.impl;

import cn.daimajiangxin.springboot.learning.model.User;
import cn.daimajiangxin.springboot.learning.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Resource
    private  UserService userService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<User>  queryWrapper=new LambdaQueryWrapper<User>();
        queryWrapper.eq(User::getUserName,username);
        User user=userService.getOne(queryWrapper);
        List<GrantedAuthority> authorities = new ArrayList<>();
        return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(),authorities );
    }
}

Java配置类

创建一个配置类,并创建SecurityFilterChain 的Bean。

package cn.daimajiangxin.springboot.learning.config;

import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig   {
    @Resource
    private UserDetailsService userDetailsService;
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorizeRequests ->
                        authorizeRequests
                                .requestMatchers("/", "/home")
                                .permitAll()
                                .anyRequest().authenticated() // 其他所有请求都需要认证
                )
                .formLogin(formLogin ->
                        formLogin
                                .loginPage("/login") // 指定登录页面
                                .permitAll() // 允许所有人访问登录页面
                )
                .logout(logout ->
                        logout
                                .permitAll() // 允许所有人访问注销URL
                )    // 注册重写后的UserDetailsService实现
                .userDetailsService(userDetailsService);
        return http.build();
        // 添加自定义过滤器或其他配置
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new StandardPasswordEncoder();
    }
}

创建登录页面

在src/main/resources/templates目录下创建一个Thymeleaf模板作为登录页面,例如login.html。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>登录</title>
</head>
<body>
<form th:action="@{/doLogin}" method="post">
    <div><label> User Name : <input type="text" name="username"/> </label></div>
    <div><label> Password: <input type="password" name="password"/> </label></div>
    <div><input type="submit" value="登录"/></div>
</form>
</body>
</html>

创建控制器

创建一个UserController,

package cn.daimajiangxin.springboot.learning.controller;

import cn.daimajiangxin.springboot.learning.model.User;
import cn.daimajiangxin.springboot.learning.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@RestController
public class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping({"/login",})
    public ModelAndView login(Model model) {
        ModelAndView mv = new ModelAndView("login");
        return mv ;
    }
    @PostMapping("/doLogin")
    public String doLogin(@RequestParam String username,@RequestParam String password) {
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("user_name",username);
        User user=  userService.getOne(queryWrapper);
        if(user==null){
            return "登录失败,用户没有找到";
        }
        if(! user.getPassword().equals(password)){
            return "登录失败,密码错误";
        }
        return "登录成功";
    }

}

登录页面

运行你的Spring Boot应用程序,用浏览器访问http://localhost:8080/login.
20240601104136


和我一起学习更多精彩知识!!!关注我公众号:代码匠心,实时获取推送。

源文来自:https://daimajiangxin.cn

源码地址:https://gitee.com/daimajiangxin/springboot-learning

与从零开始学Spring Boot系列-集成Spring Security实现用户认证与授权相似的内容:

从零开始学Spring Boot系列-集成Spring Security实现用户认证与授权

在Web应用程序中,安全性是一个至关重要的方面。Spring Security是Spring框架的一个子项目,用于提供安全访问控制的功能。通过集成Spring Security,我们可以轻松实现用户认证、授权、加密、会话管理等安全功能。本篇文章将指导大家从零开始,在Spring Boot项目中集成S

《系列二》-- 6、从零开始的 bean 创建

[TOC] > 阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。 写在开始前的话: 阅读spring 源码实在是一件庞大的工作,不说全部内容,单就最基本核心部分包含的东西就需要很长时间去消化了

[转帖]从零开始学nginx

1. nginx简介 nginx(发音同engine x)是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like协议下发行。 nginx由俄罗斯的程序设计师Igor Sysoev所开发,最初供俄国大型的入口网站及搜寻引擎Rambler使用。 第

从零开始带你上手体验Sermant自定义插件开发

本文对Sermant的自定义插件开发的流程进行了体验和探索,包括项目编译、运行、动态配置验证、插件拦截原理等内容,希望对初次体验Sermant高效开发插件的开发者有所帮助。

从零开始写 Docker(十八)---容器网络实现(下):为容器插上”网线“

本文为从零开始写 Docker 系列第十八篇,利用 linux 下的 Veth、Bridge、iptables 等等相关技术,构建容器网络模型,为容器插上”网线“。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实

从零开始写 Docker(十七)---容器网络实现(中):为容器插上”网线“

本文为从零开始写 Docker 系列第十七篇,利用 linux 下的 Veth、Bridge、iptables 等等相关技术,构建容器网络模型,为容器插上”网线“。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实

从零开始写 Docker(十六)---容器网络实现(上):为容器插上”网线”

本文为从零开始写 Docker 系列第十六篇,利用 linux 下的 Veth、Bridge、iptables 等等相关技术,构建容器网络模型,为容器插上”网线“。

从零开始写 Docker(十五)---实现 mydocker run -e 支持环境变量传递

本文为从零开始写 Docker 系列第十五篇,实现 mydocker run -e, 支持在启动容器时指定环境变量,让容器内运行的程序可以使用外部传递的环境变量。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现

从零开始写 Docker(十四)---重构:实现容器间 rootfs 隔离

本文为从零开始写 Docker 系列第十四篇,实现容器间的 rootfs 隔离,使得多个容器间互不影响。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识: 核心原理:深入理解 Docker 核心原

从零开始写 Docker(十三)---实现 mydocker rm 删除容器

本文为从零开始写 Docker 系列第十三篇,实现类似 docker rm 的功能,使得我们能够删除容器。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识: 核心原理:深入理解 Docker 核心