天天看點

Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結

本文來說下Spring Security:基于MySQL資料庫的身份認證和角色授權 。本文為了上手簡單,隻用了一張user表。

文章目錄

  • 概述
  • 建立項目
  • 基于資料庫的身份認證
  • 本文小結

概述

需求緣起

在前面我們使用基于記憶體的方式體驗了下Spring Security,在實際項目中,都是需要資料庫進行操作的。

編碼思路

本節使用MySQL資料庫進行操作,需要添加MySQL資料庫的驅動包以及配置好資料源和mybatis。

建立項目

建立一個 SpringBoot 子產品項目,選擇相關依賴:
Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結

先搭建項目正常通路,在pom.xml中,先把Spring Security依賴注釋

Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結
建立一張使用者表,并且在裡面添加兩條資料

在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');

           
Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結
建立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

Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結

基于資料庫的身份認證

把pom.xml中的Spring Security依賴注釋去掉
Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結
出現預設的登入頁面
Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結
自定義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資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結

輸入正确的使用者名和密碼,可以登入。

Spring Security:基于MySQL資料庫的身份認證概述建立項目基于資料庫的身份認證本文小結

本文小結

本文簡單介紹了Spring Security,基于MySQL資料庫的身份認證,後面會在此基礎之上進行詳細的後續知識介紹。