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實現類)