javascript
SpringBoot-Security 具体案例、 实现安全框架、权限控制、aop切入
SpringBoot-Security 具體案例、 實現安全框架、權限控制、aop切入
SpringBoot-Security介紹
Security 官方序言
? 安全是一個不斷變化的目標,追求一個全面的、系統范圍的方法很重要。在安全領域,我們鼓勵您采用“安全層”,這樣每個層都可以盡可能地保證自身的安全性,并且連續的層提供額外的安全性。每一層的安全性越“嚴格”,您的應用程序就越健壯和安全。在底層,為了減少中間人攻擊,你需要處理諸如傳輸安全和系統辨識等問題。接下來,您將通常使用防火墻,也許是通過 vpn 或 IP 安全性來確保只有經過授權的系統才能嘗試連接。在公司環境中,您可以部署 DMZ 來將面向公共的服務器與后端數據庫和應用程序服務器分開。您的操作系統也將發揮關鍵作用,解決諸如作為非特權用戶運行進程和最大化文件系統安全性等問題。操作系統通常也會配置自己的防火墻。希望在某個地方,你可以嘗試阻止針對系統的分布式拒絕服務攻擊攻擊和暴力破解。入侵預防系統安全協議對于監控和響應攻擊也特別有用,這樣的系統能夠采取保護措施,比如實時阻止違規的 TCP/IP 地址。轉移到較高的層,您的 Java 虛擬機有望被配置為最小化授予不同 Java 類型的權限,然后您的應用程序將添加自己的問題域特定的安全配置。Spring Security 使后一個領域——應用程序安全性——更加容易。
? 人們使用 Spring Security 有很多原因,但是大多數人是在發現 Java EE 的 Servlet 規范或 EJB 規范的安全特性之后才開始使用這個項目的,這些特性缺乏典型的企業應用場景所需要的深度。雖然提到了這些標準,但重要的是要認識到它們在 WAR 或 EAR 級別上是不可移植的。因此,如果切換服務器環境,在新的目標環境中重新配置應用程序的安全性通常需要做大量工作。使用 Spring Security 克服了這些問題,并且還為您帶來了許多其他有用的、可定制的安全特性。
? 您可能知道應用程序安全性的兩個主要方面是“身份驗證”和“授權”(或“訪問控制”)。這是 Spring Security 的兩個主要目標。“身份驗證”是建立一個主體的過程,這個主體就是他們聲稱的那個人(“主體”通常指一個用戶、設備或者其他能夠在你的應用程序中執行某個操作的系統)。“授權”是指決定是否允許主體在應用程序中執行操作的過程。為了達到需要作出授權決定的地步,認證過程已經確定了主體的身份。這些概念是常見的,而且根本不是 Spring Security 特有的。
(自己看的時候,蠻喜歡就加在這篇文章的開頭拉。)
文章是我在security 5.0.5. RELEASE 版本文檔里看到的 。
https://docs.spring.io/spring-security/site/docs/5.0.5.RELEASE/reference/htmlsingle/
文章簡介
本文講的是Spring Boot集成Spring-Security 框架。內容不牽扯到過多具體原理講解,只是做了簡單概述。
適合于初學者,狀態大概:對這個不是很懂,但是暫時需要在項目中使用Spring-Boot-Security。
案例里有具體的數據庫角色表 、權限表、資源表 是可以切入到已有項目的。
而且是添加注解的方式。
流程、原理等等。我應該也會去寫滴,相信我… 對這個東東流程、原理,還是非常好奇的。
當然看完就好奇的就馬上去Debug吧 奧利給!!!
項目中有一行代碼用到了 jdk 8 中的 Optional 我之前寫了文章講解
這正好是一次實用。 大家可以看一看。
https://blog.csdn.net/weixin_45821811/article/details/115656637
數據庫、表
我之前已經寫完表的文章。如下
https://blog.csdn.net/weixin_45821811/article/details/115737401
步驟
1、創建Spring-boot項目
? 工程結構圖
?
2、導入依賴
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency></dependencies>3、yaml配置文件
server:port: 8787spring:datasource: #自己的數據庫名 自己的數據庫密碼 url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false&characterEncoding=utf8&serverTimezone=GMTpassword: 123456username: root4、config
-
WebConfig
@Configuration // 相當于springmvc 文件 public class WebConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("redirect:/login");} } -
WebSecurityConfig 安全配置
@Configuration @EnableWebSecurity // 開啟WebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) // 這個開啟權限注解 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable(). //屏蔽csrfauthorizeRequests() // .antMatchers("/r/r1").hasAnyAuthority("p1") // 這種是沒有開啟權限注解 沒有添加權限注解的方法 // .antMatchers("/r/r2").hasAnyAuthority("p2") // .antMatchers("/r/r3").hasAnyAuthority("p1","p2").antMatchers("/r/**").authenticated().anyRequest().permitAll().and().formLogin().permitAll().and().logout().logoutUrl("/logout") // 退出url.logoutSuccessUrl("/logout-success"); // 自定義登錄成功的配置 成功后 轉向這個url} }
5、pojo層
-
? MyUser 用戶
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true)// 鏈式 public class MyUser {private String id;private String username;private String password;private String fullname;private String mobile; } -
PermissionDto 資源權限
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true)// 鏈式 public class PermissionDto {private String id;private String code;private String description;private String url; }
6、Dao層
@Mapper public interface MyUserDao {@Select("select * from user_db where username=#{username}")Optional<MyUser> getUserByName(String username);// 這里是多表聯查 查詢當前角色擁有的權限 表的結構在我另一篇文章有說明@Select("SELECT * FROM t_permission WHERE id IN( SELECT permission_id FROM t_role_permission WHERE role_id IN(SELECT role_id FROM t_user_role WHERE user_id = #{userId} ))")List<PermissionDto> findPermissionsByUserId(String userId); }7、Service
@Configuration public class SpringDataMyUserDetailsService implements UserDetailsService {@AutowiredMyUserDao userDao;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {Optional<MyUser> user = userDao.getUserByName(username);if (user.isPresent()) {// 判空操作 這個是jdk8的一個新特性是 在我一篇文章中有講MyUser myUser = user.get(); // 取出操作List<PermissionDto> list = userDao.findPermissionsByUserId(myUser.getId());System.out.println("list==>" + list.toString());//list==>[PermissionDto(id=1, code=p1, description=測試資源1, url=/r/r1)]List<String> permissions = new ArrayList<>();list.forEach(p -> permissions.add(p.getCode()));System.out.println("permissions===>" + permissions.toString());//permissions===>[p1]// 這里之所以轉成數組 是因為 構建 UserDetails 時//.authorities(perarray) 這個添加權限的地方是可以添加一個數組的 更加方便我們個性定//參數:權限–此用戶的權限(即ROLE_USER,ROLE_ADMIN等)。 不能為空或包含空值// public UserBuilder authorities(String... authorities) {// return authorities(AuthorityUtils.createAuthorityList(authorities));// }String[] perarray = new String[permissions.size()];permissions.toArray(perarray);//創建userDetailsUserDetails userDetails =User.withUsername(myUser.getUsername()).password( BCrypt.hashpw(myUser.getPassword(), BCrypt.gensalt()) ).authorities(perarray).build();return userDetails;}return null;} }8、Controller層
@RestController public class LoginController {//后端這返回類型 大家都知道吧 我這里是寫的文本 json 是application/json 這種 還有這請求格式 我大都是復制 就不是那種restful 風格拉// 大家使用 自行修改哦@RequestMapping(value = "/login-success", produces = "text/plain;charset=utf-8")public String loginSuccess(){return getUsername()+"登錄成功";}@RequestMapping(value = "/logout-success", produces = "text/plain;charset=utf-8")public String logout(){return "退出成功";}@RequestMapping(value = "/r/r1", produces = "text/plain;charset=utf-8") // @PreAuthorize("isAnonymous()")// 匿名訪問@PreAuthorize("hasAuthority('p1')" )public String r1(){return getUsername()+"資源1";}@RequestMapping(value = "/r/r2", produces = "text/plain;charset=utf-8")@PreAuthorize(" hasAuthority('p2')" )public String r2(){return getUsername()+"資源2";}@RequestMapping(value = "/r/r3", produces = "text/plain;charset=utf-8")@PreAuthorize("hasAuthority('p1') or hasAuthority('p2')" )public String r3(){return getUsername()+"資源3";}// 這個是只要認證通過都可以訪問 不需要主體帶有什么權限@RequestMapping(value = "/r/r4", produces = "text/plain;charset=utf-8")public String r4(){return getUsername()+"資源4";}private String getUsername(){String username=null;//當前通過的用戶身份Authentication authentication = SecurityContextHolder.getContext().getAuthentication();Object principal = authentication.getPrincipal();if (principal==null){username="匿名";}if(principal instanceof UserDetails){UserDetails userDetails= (UserDetails)principal;username = userDetails.getUsername();}else{username= principal.toString();}return username;} }9、啟動類
@SpringBootApplication @MapperScan("com.wyh.dao") public class SecuritySpringbootApplication {public static void main(String[] args) {SpringApplication.run(SecuritySpringbootApplication.class, args);}}接下來就是測試哩。還有我的自言自語…
測試
認證
認證成功
認證錯誤
退出
授權
admin 有p1 權限 能夠訪問 /r/r1 資源
admin 沒有p2 權限 訪問不了 /r/r2 資源
/r/r3 是有p1 權限或者 有p2權限都是能夠訪問的 但是沒有的話是不能訪問的
/r/r4 是只要身份認證通過就是能訪問的
自言自語
每天記錄一下自己的生活 也開始習慣每天這里寫寫 那里寫寫的感覺。
寫這些一開始是想著方便自己看 但是寫著寫著就開始想要人來關注來看。
比起一開始隨隨便便寫 現在的話要好一些拉。
就突然想把自己的知道的東西都記錄下來,可能是想讓人知道吧。
需要學的東西多的多啊。
繼續加油哦。
總結
以上是生活随笔為你收集整理的SpringBoot-Security 具体案例、 实现安全框架、权限控制、aop切入的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-Security 简介、入
- 下一篇: MySQL 数据库的操作 连接、新增