当前位置:   article > 正文

【Spring Security】springboot + mybatis-plus + mysql 密码加密存储下的数据库用户验证登录_springboot 登录验证简单实现

springboot 登录验证简单实现

在这里插入图片描述

前言

回顾:

【Spring Security】springboot + mybatis-plus + mysql 从数据库读取用户信息验证登录

本节实现 Spring Security 密码加密存储下的数据库用户验证登录,仅实现功能,不完善。

配置

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-security-learning</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-security-02</module>
        <module>spring-security-01</module>
        <module>spring-security-03</module>
        <module>spring-security-04</module>
        <module>spring-security-05</module>
    </modules>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

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

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.80</version>
        </dependency>

        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>
    </dependencies>

</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

application.properties

#spring.datasource.name=mysql
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowMultiQueries=true
spring.datasource.username=xxxx
spring.datasource.password=xxxx

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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="org.sample.dao.entity.UserPattern">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="org.sample.dao.entity.UserPattern">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="passwd" property="passwd" />
        <result column="enabled" property="enabled" />
        <result column="account_non_expired" property="account_non_expired" />
        <result column="account_non_locked" property="account_non_locked" />
        <result column="credentials_non_expired" property="credentials_non_expired" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, username, passwd, enabled, account_non_expired, account_non_locked, credentials_non_expired
    </sql>

</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

编码

config.SecurityConfig

package org.sample.config;

import com.alibaba.fastjson.JSON;
import org.sample.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.io.PrintWriter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * PasswordEncoder 是密码加密接口,因为我们是循序渐进的,我这里先用无加密实例
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 方法二
     * 实现configure(AuthenticationManagerBuilder auth)配置方法
     * 配置文件中的默认用户和默认密码注释掉了
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    /**
     * 方法一
     * auth.userDetailsService(userDetailsService())
     */
//    @Bean
//    public UserDetailsService userDetailsService(){
//        return new UserDetailsService() {
//            // username是用户登录时填的用户名
//            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//                UserPattern user = new UserPattern();
//                user.setUsername("mike");
//                user.setPassword("123456");
//                try {
//                    user = userService.loadByUserName(username);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//
//                // 如果查不到用户名,这里可以抛出UsernameNotFoundException异常
//                // 根据username查询权限,这里假设从任意位置查到权限是auth
//                List<GrantedAuthority> authorities = new ArrayList<>();
//                authorities.add(new SimpleGrantedAuthority("auth"));
//                // User是系统自带的UserDetails实现类,4个状态其中一个为false就会抛异常
//                return new User(user.getUsername(), user.getPassword(), true, true, true, true, authorities);
//            }
//        };
//    }

    /**
     * 通过HttpSecurity 对象,获取到表单登录配置对象,修改对应的用户名和密码参数名称,即可完成自定义用户名和密码参数名称
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .successHandler((req,resp,authentication)->{
                    Object principal = authentication.getPrincipal();
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write(JSON.toJSONString(principal));
                    out.flush();
                    out.close();
                })
                .failureHandler((req, resp, e) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write(JSON.toJSONString(e));
                    out.flush();
                    out.close();
                })
                .permitAll()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint((req, resp, authException) -> {
                            resp.setContentType("application/json;charset=utf-8");
                            PrintWriter out = resp.getWriter();
                            out.write(JSON.toJSONString("尚未登录,请先登录"));
                            out.flush();
                            out.close();
                        }
                )
                .and()
                .logout()
                .logoutSuccessHandler((req,resp,authentication)->{
                    Object principal = authentication.getPrincipal();
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write(JSON.toJSONString(principal));
                    out.flush();
                    out.close();
                })
                .and().csrf().disable()
        ;
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder b = new BCryptPasswordEncoder();
        // $2a$10$hVPr4t.E21omWtyUdEsSEeMaEVkKp4oLHNjv/hlCrnBFI4WGf583a
        String encode = b.encode("123456");
        System.out.println(encode);
        System.out.println(b.matches("123456", encode));

        String encode2 = b.encode("123456");
        System.out.println(encode2);
        System.out.println(b.matches("123456", encode2));
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142

Spring Security的配置类中的一个方法,用于配置HTTP安全和表单登录行为:

authorizeRequests()
使用 http.authorizeRequests() 方法开始配置授权规则。

antMatchers()
使用 antMatchers(“/admin/“).hasRole(“admin”) 配置对 /admin/ 开头的所有 URL 路径需要 “admin” 角色的用户才能访问。
使用 antMatchers(”/user/
”).hasRole(“user”) 配置对 /user/ 开头的所有 URL 路径需要 “user” 角色的用户才能访问。

anyRequest().authenticated()
使用 anyRequest().authenticated() 配置所有其他未明确指定授权规则的请求都需要经过身份验证。

.and()
在多个配置之间使用 .and() 连接器进行组合。

formLogin()
使用 http.formLogin() 配置表单登录的相关参数。

successHandler()
自定义登录成功的处理器,当用户成功登录时,将执行此处理器。
在这个处理器中,获取认证后的主体信息(principal),将其转换为 JSON 格式,并写入到响应中。

failureHandler()
自定义登录失败的处理器,当用户登录失败时,将执行此处理器。
在这个处理器中,获取异常信息(Exception),将其转换为 JSON 格式,并写入到响应中。

permitAll()
设置表单登录相关的所有请求都不需要权限控制。

exceptionHandling()
使用 http.exceptionHandling() 配置异常处理相关的行为。

authenticationEntryPoint()
自定义未登录时的异常处理入口点,当用户未登录且尝试访问需要身份验证的资源时,将执行此处理器。在这个处理器中,向响应中写入一条提示信息,表示用户尚未登录。

logout()
使用 http.logout() 配置登出相关的行为。

logoutSuccessHandler()
自定义登出成功的处理器,当用户成功登出时,将执行此处理器。
在这个处理器中,获取认证后的主体信息(principal),将其转换为 JSON 格式,并写入到响应中。

.csrf().disable()
禁用跨站请求伪造(CSRF)防护。
总的来说,这段代码主要实现了以下功能:

配置了授权规则,包括对特定路径的访问权限控制。自定义了表单登录的成功和失败处理器,以及未登录和登出成功的异常处理入口点。禁用了 CSRF 防护。

controller.HelloController

package org.sample.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/sayHello")
    public String sayHello(){
        return "十年生死两茫茫,不思量,自难忘----苏轼,hello";
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

dao.entity.UserPattern

package org.sample.dao.entity;

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.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * 测试用entity
 *
 * @author 
 * @since 
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName(value = "test.h_user")
public class UserPattern implements Serializable {

    /**
     * ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 用户名 userName
     */
    @TableField(value = "username")
    private String username;

    /**
     * 密码 password
     */
    @TableField(value = "passwd")
    private String password;

    @TableField(value = "enabled")
    private int enabled;

    @TableField(value = "account_non_expired")
    private int accountNonExpired;

    @TableField(value = "account_non_locked")
    private int accountNonLocked;

    @TableField(value = "credentials_non_expired")
    private int credentialsNonExpired;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

dao.mapper.UserServiceMapper


package org.sample.dao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.sample.dao.entity.UserPattern;

/**
 *
 * @author 
 * @since 
 */
public interface UserServiceMapper extends BaseMapper<UserPattern> {
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

service.UserService

package org.sample.service;

import com.baomidou.mybatisplus.extension.service.IService;
import org.sample.dao.entity.UserPattern;

/**
 *
 * @author 
 * @since 
 */
public interface UserService extends IService<UserPattern> {

    UserPattern loadByUserName(String username);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

service.Impl.UserServiceImpl

package org.sample.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.sample.dao.entity.UserPattern;
import org.sample.dao.mapper.UserServiceMapper;
import org.sample.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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 UserServiceImpl extends ServiceImpl<UserServiceMapper, UserPattern> implements UserService, UserDetailsService {

    @Autowired
    private UserServiceMapper userServiceMapper;

    /**
     * 方法一
     * auth.userDetailsService(userDetailsService())
     * @param username
     * @return
     */
    @Override
    public UserPattern loadByUserName(String username) {
        List<UserPattern> userPatterns = userServiceMapper.selectList(Wrappers.lambdaQuery(UserPattern.class)
                .likeLeft(UserPattern::getUsername, username)
                .likeRight(UserPattern::getUsername, username)
        );
        UserPattern userPattern = userPatterns.get(0);
        return userPattern;
    }

    /**
     * 方法二
     * auth.userDetailsService(userDetailsService)
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<UserPattern> userPatterns = userServiceMapper.selectList(Wrappers.lambdaQuery(UserPattern.class)
                .likeLeft(UserPattern::getUsername, username)
                .likeRight(UserPattern::getUsername, username)
        );
        UserPattern userPattern = userPatterns.get(0);
        // 如果查不到用户名,这里可以抛出UsernameNotFoundException异常
        // 根据username查询权限,这里假设从任意位置查到权限是auth
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("auth"));
        return new User(userPattern.getUsername(), userPattern.getPassword(), true, true, true, true, authorities);
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

MainApplication

package org.sample;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("org.sample.dao.mapper")
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

文件结构

在这里插入图片描述

实现

运行SecurityConfig.java

在这里插入图片描述
将一个加密密码复制,然后修改mysql数据库中的密码为加密密码:

在这里插入图片描述

运行MainApplication.java

打开postman:

调用一下接口,被未登录信息拦截:
在这里插入图片描述

我们登陆一下:

这里对用户来说密码是明文的,只是数据库中的密码为"123456"的加密密码:
在这里插入图片描述

显示登陆成功,之后再调用接口:

在这里插入图片描述
成功

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/783731
推荐阅读
相关标签
  

闽ICP备14008679号