JavaWeb進階修煉手冊38---spring-security(四)使用數據庫中的用戶進行驗證

1. 前言

通過前面的知識,我們已經能夠簡單的使用spring-security,並且整合到ssm框架中。當然,前面的例子中我們都是在內存中構造的用戶進行驗證的,也就是下面這行代碼:

<!-- 在內存中構造用戶們 -->
<security:authentication-manager>
    <security:authentication-provider>
        <security:user-service>
            <security:user name="user" password="{noop}user" authorities="ROLE_USER"/>
            <security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN"/>
        </security:user-service>
    </security:authentication-provider>
</security:authentication-manager>

實際的開發過程中,我們都是從數據庫中讀取的數據,接下來我們介紹如何實現。

2. UserDetails與UserDetailsService

在Spring Security中如果想要使用數據進行認證操作,有很多種操作方式,這裏我們介紹使用UserDetails、 UserDetailsService來完成操作。

2.1 UserDetails及其實現類User

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

UserDetails是一個接口,我們可以認爲UserDetails作用是於封裝當前進行認證的用戶信息,相當於之前構造於內存中的用戶。但由於其是一個接口,所以我們可以對其進行實現,也可以使用Spring Security內部提供的一個UserDetails的實現類User來完成操作

以下是User類的部分代碼:

public class User implements UserDetails, CredentialsContainer {

    private final String username;	//用戶登入名
    private String password;	//用戶登入密碼
    private final Set<GrantedAuthority> authorities;  //用戶所基本的權限,比如:ROLE_USER
    private final boolean accountNonExpired;	 	//帳戶是否過期    
    private final boolean accountNonLocked; 		//帳戶是否鎖定
    private final boolean credentialsNonExpired; 	//認證是否過期    
    private final boolean enabled; 					//帳戶是否可用

2.2 UserDetailsService

UserDetailsService:

public interface UserDetailsService {        

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; 
}

UserDetailsService是一個接口,用來讓spring-security知道從哪裏獲取數據庫中的用戶。由此,spring-security想要知道根據登錄名和密碼是否有該用戶時,會調用UserDetailsService的實現類,事實上之前用的構造於內存中的用戶是spring-security對該接口的動態代理實現的。

所以,我們必須編寫UserDetailsService的實現類。

3. 使用數據庫中的用戶進行驗證實現步驟

在這裏插入圖片描述

3.1 第一步:編寫UserDetailsService的實現類:UserDetailsServiceImpl

package cn.wanghao.springSecurity.service.impl;

import cn.wanghao.springSecurity.dao.UserDao;
import cn.wanghao.springSecurity.domain.SysRole;
import cn.wanghao.springSecurity.domain.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
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("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser = userDao.selectByName(username);
        List<SimpleGrantedAuthority> authorities = this.getAuthority(sysUser.getRoles());
        User user = new User(sysUser.getUserName(), "{noop}" + sysUser.getPassWord(), authorities);
        return user;
    }

    private List<SimpleGrantedAuthority> getAuthority(List<SysRole> roles) {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (SysRole role : roles) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        return authorities;
    }
}

注意:上面的 sysUser.getPassWord() 前面加{noop}是因爲密碼沒有加密,明文密碼需要加這個。

3.2 第二部:更改spring-security配置文件

再在spring-security中去掉之前構造用戶於內存中,該爲從我們自定義的UserDetailsServiceImpl類的對象中獲取用戶:

<!-- 在內存中構造用戶們
<security:authentication-manager>
    <security:authentication-provider>
        <security:user-service>
            <security:user name="user" password="{noop}user" authorities="ROLE_USER"/>
            <security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN"/>
        </security:user-service>
    </security:authentication-provider>
</security:authentication-manager>-->

<!-- 從數據庫中獲取用戶 -->
<security:authentication-manager>
    <security:authentication-provider user-service-ref="userDetailsService">

    </security:authentication-provider>
</security:authentication-manager>

3.3 效果

在這裏插入圖片描述

3.4 項目源碼下載地址

鏈接:https://pan.baidu.com/s/1Xo1oVjVMvf_eM_9wHKZZqw
提取碼:r211

數據庫表如下:

sys_user表:

CREATE TABLE `sys_user` (   `id` int(32) NOT NULL
AUTO_INCREMENT,   `userName` varchar(50) CHARACTER SET utf8mb4 COLLATE
utf8mb4_0900_ai_ci NOT NULL,   `passWord` varchar(50) CHARACTER SET
utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,   PRIMARY KEY (`id`) )
ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci

sys_role表:

Create Table

CREATE TABLE `sys_role` (   `id` int(32) NOT NULL AUTO_INCREMENT,  
`name` varchar(50) NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB
AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

sys_user_role表:

CREATE TABLE `sys_user_role` (   `user_id` int(32) NOT NULL,  
`role_id` int(32) NOT NULL,   PRIMARY KEY (`user_id`,`role_id`),   KEY
`role_id` (`role_id`),   CONSTRAINT `sys_user_role_ibfk_1` FOREIGN KEY
(`user_id`) REFERENCES `sys_user` (`id`),   CONSTRAINT
`sys_user_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role`
(`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章