SpringSecurity實現(xiàn)自定義數(shù)據(jù)源實戰(zhàn)指南
Spring Security簡介
Java中的安全框架通常是指解決Web應用安全問題的框架。自行實現(xiàn)Web應用的安全性并不容易,需要考慮不同的認證和授權機制、網(wǎng)絡關鍵數(shù)據(jù)傳輸加密等多方面的問題。
Java中常用的安全框架有Spring Security和Shiro,這兩個安全框架都提供了強大功能,可以很容易實現(xiàn)Web應用的很多安全防護。下面對這兩個安全框架的特點進行講解
Spring Security是Spring生態(tài)系統(tǒng)中重要的一員,是一個基于AOP思想和Servlet過濾器實現(xiàn)的安全框架,它提供了完善的認證機制和方法級的授權功能,是一款非常優(yōu)秀的權限管理框架。
在進行安全管理的過程中都涉及權限管理的兩個重要概念:Authentication(認證)
和Authorization(授權)。權限管理是指根據(jù)系統(tǒng)設置的安全規(guī)則或者安全策略,用戶可以訪問且只能訪問自己被授權的資源。
實現(xiàn)權限管理通常需要三個對象,分別為用戶、角色、權限,這三個對象的說明如下。
- 用戶:主要包含用戶名、密碼和當前用戶的角色信息,可以實現(xiàn)認證操作。
- 角色:主要包含角色名稱、角色描述和當前角色擁有的權限信息,可以實現(xiàn)授權操作。
- 權限:權限也可以稱為菜單,主要包含當前權限名稱、url地址等信息,可以實現(xiàn)動態(tài)展示菜單。
一、SQL數(shù)據(jù)表的設計
-- 創(chuàng)建用戶表
CREATE TABLE `user` (
-- 主鍵id,自增
`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '用戶id',
-- 用戶名字段
`username` VARCHAR(32) DEFAULT NULL COMMENT '用戶名',
-- 密碼字段(建議存儲加密后的密碼)
`password` VARCHAR(255) DEFAULT NULL COMMENT '密碼',
-- 賬戶啟用狀態(tài):1=啟用,0=禁用
`enabled` TINYINT(1) DEFAULT NULL COMMENT '是否可用',
-- 賬戶未過期標志:1=未過期,0=已過期
`accountNonExpired` TINYINT(1) DEFAULT NULL COMMENT '賬戶過期',
-- 賬戶未鎖定標志:1=未鎖定,0=已鎖定
`accountNonLocked` TINYINT(1) DEFAULT NULL COMMENT '賬戶鎖定',
-- 憑證未過期標志:1=未過期,0=已過期
`credentialsNonExpired` TINYINT(1) DEFAULT NULL COMMENT '憑證過期',
-- 設置主鍵
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 創(chuàng)建角色表(使用roles避免與MySQL關鍵字沖突)
CREATE TABLE `roles` (
-- 主鍵id,自增
`id` INT(11) NOT NULL AUTO_INCREMENT,
-- 角色英文名,如ROLE_ADMIN
`name` VARCHAR(32) DEFAULT NULL,
-- 角色中文名,如管理員
`name_zh` VARCHAR(32) DEFAULT NULL,
-- 設置主鍵
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 創(chuàng)建用戶角色關聯(lián)表(多對多關系)
CREATE TABLE `user_role` (
-- 主鍵id,自增
`id` INT(11) NOT NULL AUTO_INCREMENT,
-- 用戶id,關聯(lián)user表
`uid` INT(11) DEFAULT NULL,
-- 角色id,關聯(lián)roles表
`rid` INT(11) DEFAULT NULL,
-- 設置主鍵
PRIMARY KEY (`id`),
-- 為uid字段創(chuàng)建索引,提高查詢效率
KEY `uid` (`uid`),
-- 為rid字段創(chuàng)建索引,提高查詢效率
KEY `rid` (`rid`),
-- 外鍵約束:uid引用user表的id字段
CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user` (`id`),
-- 外鍵約束:rid引用roles表的id字段
CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `roles` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- ==================== 第一步:插入用戶數(shù)據(jù) ====================
-- 插入3個測試用戶
INSERT INTO `user` (
`username`,
`password`,
`enabled`,
`accountNonExpired`,
`accountNonLocked`,
`credentialsNonExpired`
) VALUES
-- 管理員用戶:全部狀態(tài)正常
('admin', 'admin123', 1, 1, 1, 1),
-- 普通用戶:正??捎?
('zhangsan', '123456', 1, 1, 1, 1),
-- 被禁用的用戶:用于測試禁用功能
('lisi', '123456', 0, 1, 1, 1);
-- ==================== 第二步:插入角色數(shù)據(jù) ====================
-- 插入幾個常用角色
INSERT INTO `roles` (`name`, `name_zh`) VALUES
('ROLE_ADMIN', '管理員'),
('ROLE_USER', '普通用戶'),
('ROLE_GUEST', '訪客');
-- ==================== 第三步:插入用戶角色關聯(lián) ====================
-- 給用戶分配角色
INSERT INTO `user_role` (`uid`, `rid`) VALUES
-- admin用戶:同時擁有管理員和普通用戶角色
(1, 1), -- admin -> ROLE_ADMIN
(1, 2), -- admin -> ROLE_USER
-- zhangsan用戶:只有普通用戶角色
(2, 2), -- zhangsan -> ROLE_USER
-- lisi用戶:只有訪客角色
(3, 3); -- lisi -> ROLE_GUEST二、引入Maven依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>三、配置yml文件
spring:
application:
name: SpringSecurity
datasource:
url: jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: com.example.springsecurity.mapper/**/*.xml四、編寫實體類、mapper.xml、mapper層
package com.example.springsecurity.entity;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Roles {
private Integer id;
private String name;
private String nameZh;
}package com.example.springsecurity.entity;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
@ToString
// 自定義用戶User
public class User implements UserDetails {/*這里繼承UserDetails是因為SpringSecurity低層只認這個,相當于不良人只認大帥不認令牌*/
private Integer id; // 用戶id
private String username; // 用戶名
private String password; // 密碼
private boolean enabled; // 是否可用
private boolean accountNonExpired; // 賬戶過期
private boolean accountNonLocked; // 賬戶鎖定
private boolean credentialsNonExpired; // 憑證過期
private List<Roles> roles = new ArrayList<>(); // 用戶角色信息
// 返回權限信息
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<SimpleGrantedAuthority> authorities = new HashSet<>();
roles.forEach(role -> {
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role.getName());
authorities.add(simpleGrantedAuthority);
});
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
public void setRoles(List<Roles> roles) {
this.roles = roles;
}
public Integer getId() {
return id;
}
public List<Roles> getRoles() {
return roles;
}
}<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springsecurity.mapper.RolesMapper">
<select id="queryRolesByName" resultType="com.example.springsecurity.entity.Roles">
select
r.id,
r.name,
r.name_zh
from
roles r,user_role `ur`
where
r.id = `ur`.rid
and
ur.uid = #{uid}
</select>
</mapper><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springsecurity.mapper.UserMapper">
<select id="queryUserByName" resultType="com.example.springsecurity.entity.User">
select * from user <if test="username !=null and username !=''">
<where>
username = #{username}
</where>
limit 1
</if>
</select>
</mapper>public interface RolesMapper {
List<Roles> queryRolesByName(@Param("uid") Integer uid);
}public interface UserMapper {
User queryUserByName(@Param("username") String username);
}五、編寫service層
@Service
@RequiredArgsConstructor//lombok自動生成構造函數(shù)
public class MyDetailsService implements UserDetailsService {
private final UserMapper userMapper;
private final RolesMapper rolesMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("username:========"+username);
User user = userMapper.queryUserByName(username);
if(ObjectUtil.isEmpty(user))
{
throw new UsernameNotFoundException("用戶不存在");
}
//這里因為沒有配置密碼格式,后臺數(shù)據(jù)庫如果是明文的話,就需要用這個暫時“過渡”一下
user.setPassword("{noop}" + user.getPassword());
List<Roles> roles = rolesMapper.queryRolesByName(user.getId());
user.setRoles(roles);
return user;
}
}六、測試運行
到此這篇關于SpringSecurity實現(xiàn)自定義數(shù)據(jù)源的文章就介紹到這了,更多相關SpringSecurity自定義數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
已有的springcloud+mybatis項目升級為mybatis-plus的方法
這篇文章主要介紹了已有的springcloud+mybatis項目升級為mybatis-plus,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03
Java實現(xiàn)前端jsencrypt.js加密后端解密的示例代碼
這篇文章主要為大家詳細介紹了如何利用jsencrypt.js實現(xiàn)前端加密,利用Java實現(xiàn)后端解密的功能,文中的示例代碼講解詳細,需要的可以參考一下2022-09-09
淺析Java?NIO?直接緩沖區(qū)和非直接緩沖區(qū)
本篇文章主要為大家介紹了Java?NIO?中直接緩沖區(qū)和非直接緩沖區(qū)的定義以及使用流程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-11-11
IDEA 集成log4j將SQL語句打印在控制臺上的實現(xiàn)操作
這篇文章主要介紹了IDEA 集成log4j將SQL語句打印在控制臺上的實現(xiàn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Mybatis 的 Interceptor(攔截器) 與 JSqlparser&
MyBatis插件提供了在SQL執(zhí)行前進行攔截、擴展的功能,允許用戶自定義邏輯處理,本文介紹Mybatis 的 Interceptor(攔截器) 與 JSqlparser 結(jié)合解析SQL 使SpringBoot項目多數(shù)據(jù)庫兼容的嘗試(推薦),感興趣的朋友跟隨小編一起看看吧2026-01-01
Dubbo無法訪問遠程Zookeeper已注冊服務的問題解決方案
今天小編就為大家分享一篇關于Dubbo無法訪問遠程Zookeeper已注冊服務的問題解決方案,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03
Spring組件實例化擴展點之InstantiationAwareBeanPostProcessor使用場景解析
InstantiationAwareBeanPostProcessor是Spring 生命周期中的一個關鍵擴展接口,繼承自 BeanPostProcessor,這篇文章主要介紹了Spring組件實例化擴展點之InstantiationAwareBeanPostProcessor使用場景解析,需要的朋友可以參考下2025-06-06

