spring security 6.3.3

spring security 6.3.3 登录用户简单校验小例子

项目结构

在这里插入图片描述
在这里插入图片描述

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.security</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>
	<url/>
	<licenses>
		<license/>
	</licenses>
	<developers>
		<developer/>
	</developers>
	<scm>
		<connection/>
		<developerConnection/>
		<tag/>
		<url/>
	</scm>
	<properties>
		<java.version>21</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>3.0.3</version>
		</dependency>
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity6</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.fastjson2</groupId>
			<artifactId>fastjson2</artifactId>
			<version>2.0.51</version>
		</dependency>
		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter-test</artifactId>
			<version>3.0.3</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

	<repositories>
		<repository>
			<id>maven_central</id>
			<name>Maven Central</name>
			<url>https://repo.maven.apache.org/maven2/</url>
		</repository>
	</repositories>
</project>
application.yaml
server:
  port: 8080

#logging:
#  level:
#    root: debug

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security-demo?serverTimezone=UTC
    username: root
    password: 123456
main
package com.security;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}
自定义UserDetailsService实现类
package com.security.demo.config.authentication;

import com.security.demo.dao.DemoDao;
import com.security.demo.pojo.LoginUser;
import com.security.demo.pojo.DbUser;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Component;

import java.util.Objects;

/**
 * 实现UserDetailsService接口的自定义UserDetailsService类型的类
 * 在自定义的AuthenticationManager中会使用到该类
 * 重写了loadUserByUsername(),里边获取到从DB里查出来相同username的信息
 * 返回UserDetails类型的LoginUser,后续AuthenticationManager会自动进行是否有权限登录的校验
 */
@Component
public class LoginUserAuthorization implements UserDetailsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoginUserAuthorization.class);

    @Resource
    private DemoDao demoDao;

    @Override
    public UserDetails loadUserByUsername(String username) {
        DbUser dbUser = null;
        try {
            dbUser = demoDao.queryByName(username);
        } catch (Exception e) {
            LOGGER.error("在这里准备记录一个可能不会发生的错误");
        }
        if (Objects.isNull(dbUser)) {
            LOGGER.error("库里不存在该用户名字");
            throw new UsernameNotFoundException("用户名或密码错误");
        }
        LoginUser loginUser = new LoginUser();
        loginUser.setUser(dbUser);
        return loginUser;
    }
}
security配置类
package com.security.demo.config;

import com.security.demo.config.authentication.LoginUserAuthorization;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

/**
 *  security的配置类
 */
@Configuration
public class SecurityConfig {

    @Resource
    private LoginUserAuthorization loginUserAuthorization;

    /**
     * 定义了password使用的加密方式
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 为AuthenticationManager里定义了UserDetailsService当中方法的执行逻辑和password的加密方式
     * ProviderManager是AuthenticationManager接口的具体实现类
     * 该类里实现了authenticate方法是做具体验证的
     * @return
     */
    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(loginUserAuthorization);
        provider.setPasswordEncoder(passwordEncoder());
        return new ProviderManager(provider);
    }

    /**
     * security全是由过滤器链的方式实现的
     * 该例中只做了一些最简单的配置
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        //本地测试关了csrf
        http.csrf(AbstractHttpConfigurer::disable);
                                        //只允许/demo/register接口可以不受任何限制的访问
        http.authorizeHttpRequests(r -> r.requestMatchers("/demo/register").permitAll()
                                        //对于其它任何接口的访问都要经过身份认证方可
                                         .anyRequest().authenticated());
        //使用security美观简洁的默认登录页
        http.formLogin(Customizer.withDefaults());
        //返回配置好的过滤器链逻辑
        return http.build();
    }
}
pojo - DbUser
package com.security.demo.pojo;

import java.io.Serializable;

/**
 * 和数据库里所有字段分别对应的实体类
 */
public class DbUser implements Serializable {

    private int id;
    private String username;
    private String password;
    private String source;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    @Override
    public String toString() {
        return "DbUser{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", source='" + source + '\'' +
                '}';
    }
}
pojo - LoginUser
package com.security.demo.pojo;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * 实现了UserDetails接口的实体类,以供security用来做后续是否有权限登录的校验
 */
public class LoginUser implements Serializable, UserDetails {

    /**
     * 使用DbUser做为该实体类的字段
     * 因为LoginUser的getUsername()和getPassword()两个方法返回的值
     * 可以从DbUser里获得
     */
    private DbUser dbUser;

    public DbUser getUser() {
        return dbUser;
    }

    public void setUser(DbUser dbUser) {
        this.dbUser = dbUser;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of();
    }

    @Override
    public String getPassword() {
        return dbUser.getPassword();
    }

    @Override
    public String getUsername() {
        return dbUser.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return UserDetails.super.isAccountNonExpired();
    }

    @Override
    public boolean isAccountNonLocked() {
        return UserDetails.super.isAccountNonLocked();
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return UserDetails.super.isCredentialsNonExpired();
    }

    @Override
    public boolean isEnabled() {
        return UserDetails.super.isEnabled();
    }

    @Override
    public String toString() {
        return "LoginUser{" + "DbUser=" + dbUser + "}";
    }
}
controller
package com.security.demo.controller;

import com.alibaba.fastjson2.JSON;
import com.security.demo.pojo.DbUser;
import com.security.demo.service.DemoService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/demo")
public class DemoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);

    @Resource
    private DemoService demoService;

    /**
     * 获取所有已存在的用户
     * @return
     */
    @RequestMapping("/list")
    public String list() {
        List<DbUser> dbUsers = demoService.queryAll();
        return JSON.toJSONString(dbUsers);
    }

    /**
     * 注册一个新用户
     * @param dbUser
     * @return
     */
    @RequestMapping("/register")
    public String register(@RequestBody DbUser dbUser) {
        String username = dbUser.getUsername();
        int row = demoService.register(dbUser);
        if (row == 0) {
            username = username.concat(": 注册失败,用户名已存在");
            LOGGER.error("{}:", username);
        }
        if (row == 1) {
            username = username.concat(": 注册成功");
            LOGGER.info("{}:", username);
        }
        return username;
    }
}
service
package com.security.demo.service;

import com.security.demo.pojo.DbUser;

import java.util.List;

public interface DemoService {

    List<DbUser> queryAll();

    int register(DbUser dbUser);
}
service impl
package com.security.demo.service.impl;

import com.security.demo.pojo.DbUser;
import com.security.demo.dao.DemoDao;
import com.security.demo.service.DemoService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

@Service
public class DemoServiceImpl implements DemoService {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoServiceImpl.class);

    @Resource
    private DemoDao demoDao;

    @Resource
    private PasswordEncoder passwordEncoder;

    /**
     * 获取所有用户信息
     * @return
     */
    @Override
    public List<DbUser> queryAll() {
        return demoDao.queryAll();
    }

    /**
     * 注册一个新用户
     * @param dbUser
     * @return
     */
    @Override
    public int register(DbUser dbUser) {
        int row = 0;
        if (checkUserNameIsExist(dbUser.getUsername())) {
            return row;
        }
        try {
            String password = dbUser.getPassword();
            String encode = passwordEncoder.encode(password);
            dbUser.setPassword(encode);
            row = demoDao.register(dbUser);
        } catch (Exception e) {
            LOGGER.error("用户在注册时出现异常");
        }
        return row;
    }

    /**
     * 在注册的时候检查该用户名字是否已存在
     * @param username
     * @return
     */
    private boolean checkUserNameIsExist(String username) {
        boolean result = false;
        try {
            DbUser dbUser = demoDao.checkUserByName(username);
            if (!Objects.isNull(dbUser)) {
                result = true;
                LOGGER.error("新用户名字已存在");
            }
        } catch (Exception e) {
            LOGGER.error("在这里准备记录一个可能不会发生的错误");
        }
        return result;
    }
}
dao
package com.security.demo.dao;

import com.security.demo.pojo.DbUser;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface DemoDao {

    //获取所有用户信息
    List<DbUser> queryAll();

    //根据username获取对应的用户信息
    DbUser queryByName(String username);

    //注册一个新用户
    int register(DbUser dbUser);

    //检查username是否已存在
    DbUser checkUserByName(String username);
}
resources - dao
<?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="com.security.demo.dao.DemoDao">

    <select id="queryAll" resultType="com.security.demo.pojo.DbUser">
        select id, username, source from user
    </select>

    <select id="queryByName" parameterType="string" resultType="com.security.demo.pojo.DbUser">
        select * from user where username = #{username}
    </select>

    <insert id="register" parameterType="com.security.demo.pojo.DbUser">
        insert into user (username, password, source) values (#{username}, #{password}, #{source})
    </insert>

    <select id="checkUserByName" parameterType="string" resultType="com.security.demo.pojo.DbUser">
        select username from user where username = #{username}
    </select>
    
</mapper>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值