Spring Security:基于MySQL数据库的身份认证

本文来说下Spring Security:基于MySQL数据库的身份认证和角色授权 。本文为了上手简单,只用了一张user表。


概述

需求缘起

在前面我们使用基于内存的方式体验了下Spring Security,在实际项目中,都是需要数据库进行操作的。

编码思路

本节使用MySQL数据库进行操作,需要添加MySQL数据库的驱动包以及配置好数据源和mybatis。


创建项目

创建一个 SpringBoot 模块项目,选择相关依赖:

在这里插入图片描述
先搭建项目正常访问,在pom.xml中,先把Spring Security依赖注释

在这里插入图片描述

创建一张用户表,并且在里面添加两条数据

在MySQL数据库中创建一张用户表,id主键自增,并添加两个用户如下:

create database Security;

use Security;

drop table if exists user;

create table user
(
    id       int auto_increment primary key comment '用户ID',
    username varchar(20) comment '用户名字',
    password varchar(100) comment '用户密码(加密后的)',
    role     varchar(10) comment '用户角色(可以把这个抽出来,因为一个用户可能不止一个角色)'
);

insert into user (username, password, role)
VALUES ('root', '123456', 'root'),
       ('admin', '123456', 'admin');

在这里插入图片描述

创建pojo实体类

创建一个创建pojo实体类

package cn.wideth.entity.security;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {

    private int id;

    private String username;

    private String password;

    private String role;
}

创建UserMapper接口

package cn.wideth.mapper;

import cn.wideth.entity.security.UserInfo;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMapper {

    //通过用户名查询用户
    UserInfo getUserByName(@Param("username") String username);

}

创建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.wideth.mapper.UserMapper">

    <select id="getUserByName" resultType="cn.wideth.entity.security.UserInfo">
        select * from user where username = #{username}
    </select>

</mapper>

创建IUserService

package cn.wideth.service;

import cn.wideth.entity.security.UserInfo;

public interface IUserService {

    UserInfo getUserByName(String username);
}

创建UserServiceImpl

package cn.wideth.service.impl;

import cn.wideth.entity.security.UserInfo;
import cn.wideth.mapper.UserMapper;
import cn.wideth.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserInfo getUserByName(String username) {

        return userMapper.getUserByName(username);
    }
}

配置application.yml文件

server:
  port: 9090

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: we18256987759
#  redis:
#    host: localhost
#    port: 6379
  profiles:
    include: config

mybatis:
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml


user:
   name: admin

编写UserController

package cn.wideth.controller;

import cn.wideth.entity.security.UserInfo;
import cn.wideth.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/user")
@Api(description = "权限测试", tags = "权限测试")
public class UserController {

    @Autowired
    private IUserService iUserService;

    @GetMapping("/getUser")
    @ApiOperation(value = "用户权限测试接口", notes = "用户权限测试接口")
    public UserInfo getUser(@RequestParam String username) {
        return iUserService.getUserByName(username);
    }
}

启动项目,进行测试

访问http://localhost:9090/api/user/getUser?username=root

在这里插入图片描述


基于数据库的身份认证

把pom.xml中的Spring Security依赖注释去掉

在这里插入图片描述

出现默认的登录页面

在这里插入图片描述

自定义LoginUserDetailsService

自定义一个UserDetailsService,取名为LoginUserDetailService,该类需要实现接口UserDetailsService,主要是实现loadUserByUsername方法

package cn.wideth.config;

import cn.wideth.entity.security.UserInfo;
import cn.wideth.service.IUserService;
import lombok.extern.slf4j.Slf4j;
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.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;


/***
 * 该类需要实现接口UserDetailsService,
 * 主要是实现loadUserByUsername方法:
 * 用来加载用户保存在数据库中的登录信息
 */
@Component
@Slf4j
public class LoginUserDetailService implements UserDetailsService {

    @Autowired
    private IUserService iUserService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        log.info("用户的登录信息被加载了");

        //通过username获取用户信息
        UserInfo userInfo = iUserService.getUserByName(username);
        log.info("数据库中保存的用户信息" + userInfo);
        if(userInfo == null) {
            throw new UsernameNotFoundException("not found");
        }

        //定义权限列表.
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 用户可以访问的资源名称(或者说用户所拥有的权限) 注意:必须"ROLE_"开头
        authorities.add(new SimpleGrantedAuthority("ROLE_"+userInfo.getRole()));

        //注意这里的user为security内置的用户类型,类型为org.springframework.security.core.userdetails.User
        User userDetails = new User(userInfo.getUsername(),passwordEncoder.encode(userInfo.getPassword()),authorities);
        log.info(userDetails.toString());
        return userDetails;
    }

}

说明:

(1) 通过username获取用户的信息。
 
(2) 定义一个User(实现了接口UserDetails)对象,返回用户的username,passowrd和权限列表。
 
(3) 需要注意,定义角色集的时候,需要添加前缀“ROLE_”。
 
(4) 这里的密码需要使用PasswordEncoder进行加密,否则会报“无效的凭证”。

配置SecurityConfig

package cn.wideth.config;

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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * Security配置
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private LoginUserDetailService loginUserDetailService;

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

     /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 从数据库读取的用户进行身份认证
        auth.userDetailsService(loginUserDetailService).passwordEncoder(passwordEncoder());
    }

}

启动项目,进行测试

输入数据库中不存在的用户名或者密码,无法登录

在这里插入图片描述
输入正确的用户名和密码,可以登录

在这里插入图片描述


本文小结

本文简单介绍了Spring Security,基于MySQL数据库的身份认证,后面会在此基础之上进行详细的后续知识介绍。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要使用Spring SecurityMySQL进行身份验证,您需要完成以下步骤: 1. 添加Spring SecurityMySQL的依赖。您可以在Maven或Gradle中添加以下依赖: ```xml <!-- Spring Security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.5.1</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.5.1</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> ``` 2. 创建一个用户。您需要在MySQL中创建一个用户,用于存储用户信息和密码。例如: ```sql CREATE TABLE users ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(100) NOT NULL, enabled TINYINT NOT NULL, PRIMARY KEY (id), UNIQUE KEY unique_username (username) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` 3. 实现UserDetailsService接口。您需要创建一个实现UserDetailsService接口的类,用于查询用户信息并返回UserDetails对象。例如: ```java @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found"); } List<GrantedAuthority> authorities = new ArrayList<>(); for (Role role : user.getRoles()) { authorities.add(new SimpleGrantedAuthority(role.getName())); } return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities); } } ``` 其中,UserRepository是一个自定义的JpaRepository,用于从数据库中查询用户信息。User类包含了用户名、密码、是否可用等信息,以及一个Role列,用于存储此用户所拥有的角色。 4. 配置Spring Security。您需要在Spring Security的配置文件中指定UserDetailsService和PasswordEncoder,并配置身份验证规则。例如: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("USER", "ADMIN") .antMatchers("/", "/login").permitAll() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/") .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/") .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 在上述配置中,我们使用了BCryptPasswordEncoder作为PasswordEncoder的实现类,用于对用户密码进行加密。在configure(HttpSecurity http)方法中,我们设置了不同URL需要的角色权限,并指定了登录页、登出URL等相关信息。 5. 创建登录页和主页。最后,您需要创建一个登录页和主页,用于用户登录和展示相关信息。例如: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <h1>Login</h1> <form method="post" action="/login"> <div> <label>Username:</label> <input type="text" name="username"> </div> <div> <label>Password:</label> <input type="password" name="password"> </div> <button type="submit">Login</button> </form> </body> </html> ``` ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Home</title> </head> <body> <h1>Welcome!</h1> <p>Logged in as: <strong><sec:authentication property="name"/></strong></p> <p>Roles: <strong><sec:authentication property="authorities"/></strong></p> <a href="/logout">Logout</a> </body> </html> ``` 以上就是使用Spring SecurityMySQL进行身份验证的基本步骤。您可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值