SpringBoot+SpringSecurity實(shí)現(xiàn)基于真實(shí)數(shù)據(jù)的授權(quán)認(rèn)證
Spring Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架,Spring Security主要做兩個(gè)事情,認(rèn)證、授權(quán)。我之前寫過一篇關(guān)于SpringSecurity的博客,但是當(dāng)時(shí)只是介紹了基于mock數(shù)據(jù)的案例,本期就來介紹一下基于真實(shí)數(shù)據(jù)的認(rèn)證授權(quán)實(shí)現(xiàn)。
(二)前期項(xiàng)目搭建為了更好的展示SpringSecurity,我們先搭建一個(gè)簡單的web項(xiàng)目出來。引入thymeleaf依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId></dependency><dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId></dependency>
新建一個(gè)登陸頁,一個(gè)首頁,然后幾個(gè)不同等級的展示頁面:login.html
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>登陸頁</title></head><body><div> <form><h2>登陸頁</h2><input type='text' placeholder='username'><input type='password' placeholder='password'><button type='button'>登陸</button> </form></div></body></html>
index.html
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>首頁</title></head><body><div> <h2>首頁</h2> <a href='http://www.aoyou183.cn/login' rel='external nofollow' >登陸</a> <div style='overflow: hidden'><div style='float: left;margin-left: 20px'> <h3>level1</h3> <a href='http://www.aoyou183.cn/level1/1' rel='external nofollow' >level-1-1</a> <hr> <a href='http://www.aoyou183.cn/level1/2' rel='external nofollow' >level-1-2</a></div><div style='float: left;margin-left: 20px'> <h3>level2</h3> <a href='http://www.aoyou183.cn/level2/1' rel='external nofollow' >level-2-1</a> <hr> <a href='http://www.aoyou183.cn/level2/2' rel='external nofollow' >level-2-2</a></div><div style='float: left;margin-left: 20px'> <h3>level3</h3> <a href='http://www.aoyou183.cn/level3/1' rel='external nofollow' >level-3-1</a> <hr> <a href='http://www.aoyou183.cn/level3/2' rel='external nofollow' >level-3-2</a></div> </div></div></body></html>
另外還有幾個(gè)不同等級的頁面
分別在body中寫上自己對應(yīng)的編號。
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>Title</title></head><body>level-1-1</body></html>
最后編寫一個(gè)controller來接收請求:
@Controllerpublic class RouteController { @RequestMapping({'/','/index'}) public String index(){return 'index'; } @RequestMapping('/login') public String toLogin(){return 'login'; } @RequestMapping('/level1/{id}') public String level1(@PathVariable('id')String id){return 'level1/'+id; } @RequestMapping('/level2/{id}') public String level2(@PathVariable('id')String id){return 'level2/'+id; } @RequestMapping('/level3/{id}') public String level3(@PathVariable('id')String id){return 'level3/'+id; }}
最終的效果如下:
最終實(shí)現(xiàn)等級不同的level頁面根據(jù)不同權(quán)限進(jìn)行跳轉(zhuǎn)。
后臺基于Mybatis和Mysql數(shù)據(jù)庫實(shí)現(xiàn),因此我們除了引入SpringSecurity的依賴之外,還需要引入Mybatis相關(guān)依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency><dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version></dependency>
在配置文件中添加數(shù)據(jù)源相關(guān)信息,以及Mybatis的配置:
spring.datasource.url=jdbc:mysql://localhost:3306/security?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8spring.datasource.username=rootspring.datasource.password=123456spring.datasource.driver-class-name=com.mysql.cj.jdbc.Drivermybatis.mapper-locations=classpath:mapper/*.xml(三)認(rèn)證與授權(quán)的實(shí)現(xiàn)
3.1 表結(jié)構(gòu)設(shè)計(jì)
認(rèn)證和授權(quán)在表設(shè)計(jì)上應(yīng)該分在兩個(gè)表內(nèi),一個(gè)表存儲用戶信息包括密碼等,另一個(gè)表存儲授權(quán)信息,還需要一個(gè)表建立用戶和授權(quán)之間的關(guān)聯(lián),給出最終的表結(jié)構(gòu):
CREATE TABLE `roles` ( `id` int(4) NOT NULL, `rolename` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `sysuser` ( `id` int(4) NOT NULL, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `user_role` ( `id` int(4) NOT NULL, `user_id` int(4) DEFAULT NULL, `role_id` int(4) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
接下來是針對這三張表的實(shí)體類,Mapper接口以及xml文件,你可以不看代碼,主要實(shí)現(xiàn)一個(gè)通過用戶名查找用戶以及相關(guān)權(quán)限的操作:
@Datapublic class Roles { private Integer id; private String roleName;}@Datapublic class SysUser { private Integer id; private String userName; private String password; private List<Roles> roles;}
Mapper接口:
public interface UserMapper { public SysUser getUserByUserName(@Param('userName') String userName);}
xml實(shí)現(xiàn):
<?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.javayz.springsecurity.mapper.UserMapper'> <resultMap type='com.javayz.springsecurity.entity.SysUser'><id property='id' column='ID'/><result property='userName' column='username'/><result property='password' column='password'/><collection property='roles' ofType='com.javayz.springsecurity.entity.Roles'> <result column='name' property='roleName'/></collection> </resultMap> <select parameterType='String' resultMap='userMap'>select sysuser.*,roles.rolenamefrom sysuserLEFT JOIN user_role on sysuser.id= user_role.user_idLEFT JOIN roles on user_role.role_id=roles.idwhere username= #{userName} </select></mapper>
3.2 認(rèn)證過程
SpringSecurity的認(rèn)證過程是這樣的,首先通過用戶名或者其他唯一的ID在數(shù)據(jù)庫里找到這個(gè)用戶,用戶的密碼以非對稱加密的方式存儲。取到用戶后將前臺傳入的密碼加密后和數(shù)據(jù)庫中已經(jīng)加密好的字段進(jìn)行對比,從而通過認(rèn)證。
上面這個(gè)過程中的第一步通過用戶名找到用戶的操作需要通過Service服務(wù)來實(shí)現(xiàn),并且這個(gè)Service服務(wù)需要繼承SpringSecurity中的UserDetailsService接口。這個(gè)接口返回一個(gè)SpringSecurity的User對象。
@Servicepublic class UserService implements UserDetailsService { @Resource private UserMapper userMapper; //根據(jù)用戶名找到對應(yīng)的用戶信息 @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {SysUser sysUser = userMapper.getUserByUserName(s);if (sysUser!=null){ List<GrantedAuthority> roles=new ArrayList<>(); sysUser.getRoles().stream().forEach(x->{roles.add(new SimpleGrantedAuthority(x.getRoleName())); }); return new User(sysUser.getUserName(),sysUser.getPassword(),roles);}throw new UsernameNotFoundException('用戶未找到'); }}
3.3 Security攔截配置
上面的步驟都完成后就開始配置Security了,寫一個(gè)配置方法SecurityConfig,代碼層面很簡單,認(rèn)證傳入userService對象,會自動把數(shù)據(jù)庫中取出的密碼和前端傳過來的密碼進(jìn)行對照。同時(shí)在userService中還傳入了roles集合,在授權(quán)處給不同的頁面附上不同的權(quán)限即可。
@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; //授權(quán) @Override protected void configure(HttpSecurity http) throws Exception {//首頁所有人都能訪問,level頁面只有有權(quán)限的人才能訪問http.authorizeRequests().antMatchers('/').permitAll().antMatchers('/level1/**').hasRole('vip1').antMatchers('/level2/**').hasRole('vip2').antMatchers('/level3/**').hasRole('vip3');//沒有權(quán)限默認(rèn)跳到登陸頁,默認(rèn)會重定向到/loginhttp.formLogin(); } //認(rèn)證 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder()); }}
3.4 其他注意點(diǎn)
我在認(rèn)證的時(shí)候使用的密碼加密方式是BCryptPasswordEncoder,因此存入數(shù)據(jù)庫中的密碼也需要被加密,常用的方式就是在注冊時(shí)通過同樣的方式對密碼進(jìn)行加密存入數(shù)據(jù)庫中:
String password='xxx';BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();String encode=bCryptPasswordEncoder.encode(password);(四)總結(jié)
SpringSecurity很強(qiáng)大,除了這種方式之外,還支持集成JWT、Oauth2等等。后續(xù)我會繼續(xù)更新,我是魚仔,我們下期再見。
到此這篇關(guān)于SpringBoot+SpringSecurity實(shí)現(xiàn)基于真實(shí)數(shù)據(jù)的授權(quán)認(rèn)證的文章就介紹到這了,更多相關(guān)SpringBoot+SpringSecurity授權(quán)認(rèn)證內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. XHTML 1.0:標(biāo)記新的開端2. CSS3實(shí)例分享之多重背景的實(shí)現(xiàn)(Multiple backgrounds)3. XML入門的常見問題(四)4. asp(vbscript)中自定義函數(shù)的默認(rèn)參數(shù)實(shí)現(xiàn)代碼5. 詳解瀏覽器的緩存機(jī)制6. php網(wǎng)絡(luò)安全中命令執(zhí)行漏洞的產(chǎn)生及本質(zhì)探究7. XML解析錯(cuò)誤:未組織好 的解決辦法8. 使用Spry輕松將XML數(shù)據(jù)顯示到HTML頁的方法9. 利用CSS3新特性創(chuàng)建透明邊框三角10. ASP基礎(chǔ)知識VBScript基本元素講解
