Spring Security極簡入門三部曲(下篇)
- 2021 年 5 月 7 日
- 筆記
- Spring Boot, spring security
Spring Security極簡入門三部曲(下篇)
前情回顧
我們已經實現的功能:
- 網站分為首頁、登陸頁、用戶頁、管理員頁、報錯頁
- 使用用戶名密碼登陸,登陸失敗報錯
- 首頁、登陸頁所有角色都能訪問
- 用戶頁需要USER或ADMIN許可權,管理員頁需要ADMIN許可權(許可權不足時跳轉至403頁面)
- 如果用戶沒有登錄,則訪問需要許可權的頁面時自動跳轉登錄頁面,登陸成功後自動跳轉至訪問的頁面
- 自定義驗證器,當黑客使用baize用戶和任意密碼登陸後,將獲取全部許可權
本次添加的功能:
從這篇部落格開始,我們將在demo2中加入資料庫得到demo3,在保留demo2的功能的基礎上,增加兩個用戶,user2,擁有USER許可權,admin2,擁有USER、ADMIN許可權,這些數據都將存入資料庫中,github項目地址
資料庫設計
回顧一下之前給出的資料庫模型
當然,本節並不會用到所有的表,規定只在用戶<->角色之間進行許可權的約束,也就是上圖的用戶表、角色表、用戶角色關係表,建表語句如下:
create table `user`(
`user_id` int(11) not null auto_increment,
`username` varchar(255) default null comment '姓名',
`password` varchar(255) default null comment '密碼',
primary key (`id`)
)engine=innodb, charset=utf8;
create table `role`(
`role_id` int(11) not null auto_increment,
`role_name` varchar(255) default null comment '角色',
primary key (`id`)
)engine=innodb, charset=utf8;
create table `user_role`(
`user_id` int(11) not null,
`role_id` int(11) not null,
primary key(`user_id`, `role_id`)
)engine=innodb, charset=utf8;
//這個密碼是用了工具類對123進行加密後的結果
insert into `user`(`user_id`, `username`, `password`)
values
(1, 'admin2', '$2a$10$h6rzOMVI5lismIclafb7duoVCgN2ShCVr4Nn2Jx772.buyaq7rZKq'),
(2, 'user2', '$2a$10$h6rzOMVI5lismIclafb7duoVCgN2ShCVr4Nn2Jx772.buyaq7rZKq');
insert into `role`(`role_id`, `role_name`)
values
(1, 'ROLE_USER'),
(2, 'ROLE_ADMIN');
insert into `user_role`(`user_id`, `role_id`)
values
(1, 1),
(1, 2),
(2, 1);
demo時刻
實現功能:github項目地址
- 從資料庫中讀取用戶名、密碼,與前端輸l入的資訊進行對比驗證(user2和admin2,密碼為123)
- 驗證通過後,登陸用戶會得到資料庫中存儲的角色資訊
demo3相比前兩個demo增加了較多的文件:
- application.yml中添加了資料庫相關的一些配置文件
- 因使用mybatis框架而添加了相關mapper,以及配合使用的實體類,service,xml文件等
- 添加了一個UserDetailsService介面的實現類MyUserDetailsService為核心類
程式碼分析
MyUserDetailsService是核心,它的主要作用就是自定義了一個資料庫驗證器加入過濾器鏈,用於驗證前端輸入的用戶名是否能在資料庫中表中查到,並且在查得用戶時去查詢角色表,為用戶賦予角色許可權(spring security會為我們做密碼錯誤時的驗證,不用人為去處理)
我們只需要在自定義的loadUserByUsername()方法中將參數s當作前端輸入的username去使用,並且最後返回一個UserDetails介面的實現類即可(該實現類記錄著用戶名、密碼、許可權列表)
/**
* UserDetailsService的實現類,用於在程式中引入一個自定義的AuthenticationProvider,實現資料庫訪問模式的驗證
*/
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private UserRoleService userRoleService;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
//從資料庫中取出用戶資訊
User user = userService.findByName(s);
//判斷用戶是否存在
if (user == null) {
throw new UsernameNotFoundException("資料庫中無此用戶!");
}
//添加許可權
List<UserRole> userRoles = userRoleService.listByUserId(user.getUserId());
for (UserRole userRole : userRoles) {
Role role = roleService.findById(userRole.getRoleId());
authorities.add(new SimpleGrantedAuthority(role.getRoleName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
}
}
小結
-
在demo2的基礎上,我們增加了兩個用戶,我們可以使用這兩個用戶進行登陸,也可以使用之前定義在記憶體中的賬戶進行登陸
-
本節的demo3看上去多了很多內容但大多都是mybatis框架的程式碼和資料庫的配置文件,請主要關注MyUserDetailsService實現類,並將其當作定義了一個資料庫驗證器類,定義了過濾器鏈中的一個驗證規則(類似於一個自定義的AuthenticationProvider實現類)