前言:mysql
利用數據庫視圖,實現web接口查詢敏感信息時動態脫敏。web
具體目標:某接口爲用戶信息查詢接口,返回敏感用戶信息(id,姓名、手機號【敏感】、身份證號【敏感】),若是web用戶爲管理員角色,則查詢後返回明文用戶信息,若是用戶爲普通用戶信息,則查詢後返回脫敏後的用戶信息。spring
具體步驟:sql
1、在mysql中新建一個用戶信息表,並添加幾條數據數據庫
2、對上表建立脫敏後的視圖,利用掩碼技術脫敏,脫敏字段爲phone和id_cardapache
create view user_info_view as select id,name,concat(left(phone,3),'****',right(phone,3)) as phone,concat(left(id_card,4),'**************') as id_card from user_info;
3、SpringBoot項目啓用SpringSecurity,在配置文件中,內存新建帳號的時候添加admin和normal兩個角色app
package Eleven.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("admin").password(passwordEncoder().encode("123456")).roles("admin"); auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("123456")).roles("normal"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 定義哪些URL須要被保護、哪些不須要被保護 .antMatchers("/login").permitAll()// 設置全部人均可以訪問登陸頁面 .anyRequest().authenticated() // 任何請求,登陸後能夠訪問 .and() .formLogin().loginPage("/login") ; } }
4、建立UserInfo的domain類dom
package Eleven.domain; public class UserInfo { private long id; private String name; private String phone; private String id_card; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getId_card() { return id_card; } public void setId_card(String id_card) { this.id_card = id_card; } }
5、建立Mapper,訪問數據庫的接口,兩個查詢方法,以便按不一樣的角色區分查詢原始表仍是脫敏後的視圖ide
package Eleven.mapper; import Eleven.domain.UserInfo; import org.apache.ibatis.annotations.*; @Mapper public interface UserMapper { //根據用戶名查詢,查詢原始表,明文顯示敏感信息 @Select("select * from user_info where name=#{name}") UserInfo findByName(String name); //根據用戶名查詢,查詢脫敏後的視圖表,脫敏顯示敏感信息 @Select("select * from user_info_view where name=#{name}") UserInfo findByNameSec(String name); }
6、建立Service 和Impl文件函數
package Eleven.service; import Eleven.domain.UserInfo; public interface UserService { public UserInfo find(String name); public UserInfo findSec(String name); }
package Eleven.impl; import Eleven.domain.UserInfo; import Eleven.mapper.UserMapper; import Eleven.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public UserInfo find(String name){ return userMapper.findByName(name); } public UserInfo findSec(String name){ return userMapper.findByNameSec(name); } }
7、建立controller文件,其中Get請求中,獲取登陸用戶的角色,不一樣的角色調用Service中不一樣的函數,最終admin用戶在數據庫原始表中執行SQL查詢,普通用戶在脫敏後的視圖中執行SQL查詢
package Eleven.controller; import Eleven.domain.User; import Eleven.domain.UserInfo; import Eleven.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/findByName") public Object findByName(String name){ /** * 獲取登陸用戶的角色,不一樣角色調用Service中不一樣的函數,最終執行不一樣的Sql查詢 */ Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth.getAuthorities().toString().equals("[ROLE_admin]")){ UserInfo userInfo = userService.find(name); return userInfo; } else if (auth.getAuthorities().toString().equals("[ROLE_normal]")){ UserInfo userInfo = userService.findSec(name); return userInfo; } else { return auth.getAuthorities().toString(); } } }
8、測試驗證
一、訪問SpringBoot WEB,進入登陸頁面
二、使用admin用戶登陸後,訪問查詢用戶信息接口,以下圖所示,返回的是明文用戶信息
三、使用user普通用戶登陸後訪問,以下圖所示,返回的是脫敏後的用戶信息
利用數據庫視圖技術實現動態脫敏,適用於web應用,適用於生產環境,可按用戶角色返回脫敏先後的查詢結果。可是全部敏感數據表均需生成視圖,額外佔用數據庫存儲空間;爲了實現目標,研發人員須要額外的開發工做量。