博客 / 詳情

返回

從零開始學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

user avatar edagarli 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.