Spring Security極簡入門三部曲(下篇)

白澤來了發表於2021-05-07

Spring Security極簡入門三部曲(下篇)

前情回顧

我們已經實現的功能:

  1. 網站分為首頁、登陸頁、使用者頁、管理員頁、報錯頁
  2. 使用使用者名稱密碼登陸,登陸失敗報錯
  3. 首頁、登陸頁所有角色都能訪問
  4. 使用者頁需要USER或ADMIN許可權,管理員頁需要ADMIN許可權(許可權不足時跳轉至403頁面)
  5. 如果使用者沒有登入,則訪問需要許可權的頁面時自動跳轉登入頁面,登陸成功後自動跳轉至訪問的頁面
  6. 自定義驗證器,當黑客使用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專案地址

  1. 從資料庫中讀取使用者名稱、密碼,與前端輸l入的資訊進行對比驗證(user2和admin2,密碼為123)
  2. 驗證通過後,登陸使用者會得到資料庫中儲存的角色資訊

demo3相比前兩個demo增加了較多的檔案:

  1. application.yml中新增了資料庫相關的一些配置檔案
  2. 因使用mybatis框架而新增了相關mapper,以及配合使用的實體類,service,xml檔案等
  3. 新增了一個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);
    }
}

小結

  1. 在demo2的基礎上,我們增加了兩個使用者,我們可以使用這兩個使用者進行登陸,也可以使用之前定義在記憶體中的賬戶進行登陸

  2. 本節的demo3看上去多了很多內容但大多都是mybatis框架的程式碼和資料庫的配置檔案,請主要關注MyUserDetailsService實現類,並將其當作定義了一個資料庫驗證器類,定義了過濾器鏈中的一個驗證規則(類似於一個自定義的AuthenticationProvider實現類)

相關文章