作为一名开发怎能不知道大名顶顶的安全框架呢?市面上流行的安全框架有:shiro和springSecurity。那么你经常用哪个框架做安全访问控制呢?因为SpringBoot集成了SpringSecurity,所以我们这次来聊聊它
概念: Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
SpringSecurity官网:官网
对应依赖 pom依赖:
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-security</artifactId > </dependency >
SpringSecurity包含的模块: 继续我们可以看到这么一幅图,可以知道它是基于servlet过滤器实现的: http配置相关: 用户密码验证:
创建项目 1.创建新的项目,选择thymelaef和SpringWeb依赖 2.新增静态资源(代码省略,主要是各角色页面,需要此部分代码可私我) 3.添加路由控制页面跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.springstudy.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;@Controller public class RouterController { @RequestMapping({"/","/index"}) public String index () { return "index" ; } @RequestMapping("/toLogin") public String toLogin () { return "views/login" ; } @RequestMapping("/level1/{id}") public String level1 (@PathVariable("id") int id) { return "views/level1/" +id; } @RequestMapping("/level2/{id}") public String level12 (@PathVariable("id") int id) { return "views/level2/" +id; } @RequestMapping("/level3/{id}") public String level3 (@PathVariable("id") int id) { return "views/level3/" +id; } }
4.启动项目查看页面效果(默认登陆用户名是user,登陆密码在控制台) 后面我们要实现对应的权限控制效果!
自定义登陆用户和密码 老是这样登不行啊,我么来自定义配置一下登陆用户名和密码
1 2 3 4 5 6 spring.thymeleaf.cache =false spring.security.user.name =admin spring.security.user.password =123456
新增SecurityConfig配置类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package com.springstudy.config;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;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;@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure (HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/" ).permitAll() .antMatchers("/level1/**" ).hasRole("guest" ) .antMatchers("/level2/**" ).hasRole("vip" ) .antMatchers("/level3/**" ).hasRole("svip" ); http.formLogin() .usernameParameter("username" ) .passwordParameter("password" ) .loginPage("/toLogin" ) .loginProcessingUrl("/login" ); http.logout().logoutSuccessUrl("/" ); http.rememberMe().rememberMeParameter("remember" ); } @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder ()) .withUser("user1" ) .password(new BCryptPasswordEncoder ().encode("123456" )) .roles("guest" ) .and() .withUser("user2" ) .password(new BCryptPasswordEncoder ().encode("123456" )) .roles("guest" ,"vip" ) .and() .withUser("user3" ) .password(new BCryptPasswordEncoder ().encode("123456" )) .roles("guest" ,"vip" ,"svip" ); } }
修改前台配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 <!DOCTYPE html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" xmlns:sec ="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1, maximum-scale=1" > <title > 首页</title > <link href ="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel ="stylesheet" > <link th:href ="@{/test/css/qinstyle.css}" rel ="stylesheet" > </head > <body > <div class ="ui container" > <div class ="ui segment" id ="index-header-nav" th:fragment ="nav-menu" > <div class ="ui secondary menu" > <a class ="item" th:href ="@{/index}" > 首页</a > <div class ="right menu" > <div sec:authorize ="!isAuthenticated()" > <a class ="item" th:href ="@{/toLogin}" > <i class ="address card icon" > </i > 登录 </a > </div > <div sec:authorize ="isAuthenticated()" > <a class ="item" > 用户名:<span sec:authentication ="principal.username" > </span > 角色:<span sec:authentication ="principal.authorities" > </span > </a > </div > <div sec:authorize ="isAuthenticated()" > <form th:action ="@{/logout}" method ="post" > <a class ="item" th:href ="@{/logout}" style ="text-decoration:underline;" > 注销 </a > </form > </div > </div > </div > </div > <div class ="ui segment" style ="text-align: center" > <h3 > Spring Security Study</h3 > </div > <div > <br > <div class ="ui three column stackable grid" > <div class ="column" sec:authorize ="hasRole('guest')" > <div class ="ui raised segment" > <div class ="ui" > <div class ="content" > <h5 class ="content" > Level 1</h5 > <hr > <div > <a th:href ="@{/level1/1}" > <i class ="bullhorn icon" > </i > Level-1-1</a > </div > <div > <a th:href ="@{/level1/2}" > <i class ="bullhorn icon" > </i > Level-1-2</a > </div > <div > <a th:href ="@{/level1/3}" > <i class ="bullhorn icon" > </i > Level-1-3</a > </div > </div > </div > </div > </div > <div class ="column" sec:authorize ="hasRole('vip')" > <div class ="ui raised segment" > <div class ="ui" > <div class ="content" > <h5 class ="content" > Level 2</h5 > <hr > <div > <a th:href ="@{/level2/1}" > <i class ="bullhorn icon" > </i > Level-2-1</a > </div > <div > <a th:href ="@{/level2/2}" > <i class ="bullhorn icon" > </i > Level-2-2</a > </div > <div > <a th:href ="@{/level2/3}" > <i class ="bullhorn icon" > </i > Level-2-3</a > </div > </div > </div > </div > </div > <div class ="column" sec:authorize ="hasRole('svip')" > <div class ="ui raised segment" > <div class ="ui" > <div class ="content" > <h5 class ="content" > Level 3</h5 > <hr > <div > <a th:href ="@{/level3/1}" > <i class ="bullhorn icon" > </i > Level-3-1</a > </div > <div > <a th:href ="@{/level3/2}" > <i class ="bullhorn icon" > </i > Level-3-2</a > </div > <div > <a th:href ="@{/level3/3}" > <i class ="bullhorn icon" > </i > Level-3-3</a > </div > </div > </div > </div > </div > </div > </div > </div > <script th:src ="@{/test/js/jquery-3.1.1.min.js}" > </script > <script th:src ="@{/test/js/semantic.min.js}" > </script > </body > </html >
重启项目验证 可以看到3个用户,可以看到不同的模块,实现了权限的控制。 注:在我们配置注销时,可以看到springSecurity已经帮我们配置好了 当然我们实际的处理方式是不同的角色配置不同的菜单,不会这么控制!这里只是举例说明Security权限控制以及thymeleaf权限控制语法
登陆页配置记住我
功能:用户没有登录的时候,就只显示导航栏!如果登录了,只显示自己权限能够看到的东西 根据不同的权限,前端展示不同的功能!
springsecrity 和 thymealef 结合:
添加依赖:
1 2 3 4 5 6 <dependency > <groupId > org.thymeleaf.extras</groupId > <artifactId > thymeleaf-extras-springsecurity5</artifactId > <version > 3.0.4.RELEASE</version > </dependency >
前端代码:
1 <input type ="checkbox" name ="remember" > 记住我
后端代码:
1 2 3 4 5 6 7 8 9 10 http.rememberMe().rememberMeParameter("remember" ); http.formLogin() .usernameParameter("username" ) .passwordParameter("password" ) .loginPage("/toLogin" ) .loginProcessingUrl("/login" );
启动测试看用户信息是否存如cookie: 可以删除cookie后刷新页面看看是否自动退出了!
退出的问题 点击退出发现报错了
这是为什么呢? 原来SpringSecurity禁止了get方式的退出,以防止 csrf 跨站伪请求!
那我们把退出操作改成表单提交的post方式请求即可;
修改index.html注销代码:
1 2 3 4 5 6 <form th:action ="@{/logout}" method ="post" > <button type ="submit" class ="def-log-out" > 注销</button > </form >
build 后再次点击注销可以验证下!
小结:Spring集成Security后,sercurity就变得轻巧了很多,且因为功能强大所以在SpringBoot中面对shrio优势明显, 像我们常见的功能:单点登陆,微信qq登陆认证等它都作了对应的支持!本次只是分享Security的初步使用!