Spring Security思維導圖
簡介
SpringSecurity是Spring下的一個安全框架,與shiro 類似,一般用於用戶認證(Authentication)和用戶授權(Authorization)兩個部分,常與與SpringBoot相整合。
初階 Spring Security
添加maven依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>重新部署,會看到一個登陸頁面。
密碼,翻看日誌可以查看到
用戶名默認為 user輸入用戶名和密碼
登錄成功
中階 Security 內存用戶名和密碼
用戶名密碼登錄
在上面的章節中,添加了Security依賴,直接就出現了登錄界面,這次讓用戶名,密碼保存到內存當中
寫一個extends WebSecurityConfigurerAdapter的配置類:
配置類內容如下
package com.example.demo.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, securedEnabled =true, jsr250Enabled =true)publicclassWebSecurityConfigextendsWebSecurityConfigurerAdapter{//密碼加密函數@BeanPasswordEncoder passwordEncoder(){returnnewBCryptPasswordEncoder();}//password為BCryptPasswordEncoder加密123後的值@Overrideprotectedvoid configure(AuthenticationManagerBuilder auth)throwsException{ auth.inMemoryAuthentication().withUser("admin").password("$2a$10$2cPRItUHyE1GSZnrYWHiQevpbxn4ikWgOa1PYL5miWvqK8GFVCWb6").roles("admin").and().withUser("java").password("$2a$10$rygGQylvmoAFmPcKQP6xvepNVAw9Bxp0sbAphxKQwhAV79Au0ECvq").roles("user");}@Overrideprotectedvoid configure(HttpSecurity http)throwsException{ http.authorizeRequests().antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").hasAnyRole("admin","user").anyRequest().authenticated()//其他路徑認證之後就可以訪問.and().formLogin().loginProcessingUrl("/doLogin")//處理登錄請求的地址.permitAll().and().csrf().disable();}}輸入用戶名,密碼,進行登錄
可以看到,登錄成功
其中,1.通過 @EnableWebSecurity註解開啟Spring Security的功能。使用@EnableGlobalMethodSecurity(prePostEnabled = true)這個註解,可以開啟security的註解,我們可以在需要控制權限的方法上面使用@PreAuthorize,@PreFilter這些註解。
2.extends 繼承 WebSecurityConfigurerAdapter 類,並重寫它的方法來設置一些web安全的細節。我們結合@EnableWebSecurity註解和繼承WebSecurityConfigurerAdapter,來給我們的系統加上基於web的安全機制。
## 角色權限控制當我們的系統功能模塊當需求發展到一定程度時,會不同的用戶,不同角色使用我們的系統。這樣就要求我們的系統可以做到,能夠對不同的系統功能模塊,開放給對應的擁有其訪問權限的用戶使用。
Spring Security提供了Spring EL表達式,允許我們在定義URL路徑訪問(@RequestMapping)的方法上面添加註解,來控制訪問權限。
在標註訪問權限時,根據對應的表達式返回結果,控制訪問權限:
true,表示有權限fasle,表示無權限
新建新的控制器
package com.example.demo.web;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test")publicclassTest{@RequestMapping("/mapping")@ResponseBodypublicString test(){return"test";}}可以看到已經訪問成功
添加權限註解
package com.example.demo.web;import org.springframework.security.access.prepost.PreAuthorize;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test")publicclassTest{@RequestMapping("/mapping")@ResponseBody@PreAuthorize("hasRole('admin')")// Spring Security默認的角色前綴是」ROLE_」,使用hasRole方法時已經默認加上了publicString test(){return"test";}}此時訪問
403錯誤
高階:使用資料庫保存用戶名和密碼
用戶表
@EntityclassUser{@Id@GeneratedValue(strategy =GenerationType.AUTO)@BeanPropertyvar id:Integer= _@BeanPropertyvar userName:String= _@BeanPropertyvar password:String= _}角色表
@EntityclassRole{@Id@GeneratedValue(strategy =GenerationType.AUTO)@BeanPropertyvar id:Integer= _@BeanPropertyvar role:String= _}用戶角色表
@EntityclassUserRole{@Id@GeneratedValue(strategy =GenerationType.AUTO)@BeanPropertyvar id:Integer= _@BeanPropertyvar userId:Integer= _@BeanPropertyvar roleId:Integer= _}更改SpringSecurity
@Overrideprotectedvoid configure(AuthenticationManagerBuilder auth)throwsException{ auth.inMemoryAuthentication().withUser("admin").password("$2a$10$2cPRItUHyE1GSZnrYWHiQevpbxn4ikWgOa1PYL5miWvqK8GFVCWb6").roles("admin").and().withUser("java").password("$2a$10$rygGQylvmoAFmPcKQP6xvepNVAw9Bxp0sbAphxKQwhAV79Au0ECvq").roles("user");}更改為
@Override@BeanpublicUserDetailsService userDetailsService(){//覆蓋寫userDetailsService方法 (1)returnnewLightSwordUserDetailService();}//AuthenticationManager使用我們的 lightSwordUserDetailService 來獲取用戶信息 auth.userDetailsService(userDetailsService());具體的 new LightSwordUserDetailService(); 實現類,需要自己進行配置
這個接口需要我們實現一個方法:loadUserByUsername。即從資料庫中取出用戶名、密碼以及權限相關的信息。最後返回一個UserDetails 實現類。
@ServiceclassLightSwordUserDetailServiceextendsUserDetailsService{@Autowiredvar userRoleDao:UserRoleDao= _@Autowiredvar userDao:UserDao= _@Autowiredvar roleDao:RoleDao= _overridedef loadUserByUsername(username:String):UserDetails={// val user = userDao.findByUsername(username) // 直接調用jpa自動生成的方法 val user = userDao.getUserByUsername(username)if(user ==null)thrownewUsernameNotFoundException(username +" not found") val authorities =new util.ArrayList[SimpleGrantedAuthority] val userRoles = userRoleDao.listByUserId(user.id)// Scala中調用java的collection類,使用scala的foreach,編譯器會提示無法找到result的foreach方法。因為這裡的userRoles的類型為java.util.List。若要將其轉換為Scala的集合,就需要增加如下語句:import scala.collection.JavaConversions._for(userRole <- userRoles){ val roleId = userRole.roleId val roleName = roleDao.findOne(roleId).roleif(!StringUtils.isEmpty(roleName)){ authorities.add(newSimpleGrantedAuthority(roleName))}System.err.println("username is "+ username +", "+ roleName)}newUser(username, user.password, authorities)}}在上方,通過內部類的方式,獲取到了一個User對象。並添加進入了UserDetails中
這樣就完成了高階教程