文章目錄
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