Spring Boot Security

本示例要内容

  • 基于角色的权限访问控制
  • 加密、解密
  • 基于Spring Boot Security 权限管理框架保护应用程序

String Security介绍

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

快速上手

1.创建表

  1. CREATE TABLE `user` (
  2. `id` bigint(11) NOT NULL AUTO_INCREMENT,
  3. `username` varchar(255) NOT NULL,
  4. `password` varchar(255) NOT NULL,
  5. PRIMARY KEY (`id`)
  6. );
  7. CREATE TABLE `role` (
  8. `id` bigint(11) NOT NULL AUTO_INCREMENT,
  9. `name` varchar(255) NOT NULL,
  10. PRIMARY KEY (`id`)
  11. );
  12. CREATE TABLE `user_role` (
  13. `user_id` bigint(11) NOT NULL,
  14. `role_id` bigint(11) NOT NULL
  15. );
  16. CREATE TABLE `role_permission` (
  17. `role_id` bigint(11) NOT NULL,
  18. `permission_id` bigint(11) NOT NULL
  19. );
  20. CREATE TABLE `permission` (
  21. `id` bigint(11) NOT NULL AUTO_INCREMENT,
  22. `url` varchar(255) NOT NULL,
  23. `name` varchar(255) NOT NULL,
  24. `description` varchar(255) NULL,
  25. `pid` bigint(11) NOT NULL,
  26. PRIMARY KEY (`id`)
  27. );

2.添加maven依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-security</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-web</artifactId>
  13. </dependency>
  14. <dependency>
  15. <groupId>org.thymeleaf.extras</groupId>
  16. <artifactId>thymeleaf-extras-security4</artifactId>
  17. </dependency>
  18. <dependency>
  19. <groupId>mysql</groupId>
  20. <artifactId>mysql-connector-java</artifactId>
  21. <scope>runtime</scope>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.projectlombok</groupId>
  25. <artifactId>lombok</artifactId>
  26. <optional>true</optional>
  27. </dependency>
  28. <dependency>
  29. <groupId>com.baomidou</groupId>
  30. <artifactId>mybatis-plus-boot-starter</artifactId>
  31. <version>3.1.2</version>
  32. </dependency>
  33. </dependencies>

3.配置文件

  1. spring:
  2. thymeleaf:
  3. encoding: UTF-8
  4. cache: false
  5. datasource:
  6. driver-class-name: com.mysql.cj.jdbc.Driver
  7. url: jdbc:mysql://localhost:3306/easy_web?useSSL=false&serverTimezone=UTC
  8. username: root
  9. password: 123456

4.自定义UserDetailsService,实现用户登录功能

  1. @Service
  2. public class MyUserDetailsService implements UserDetailsService {
  3. @Autowired
  4. private UserMapper userMapper;
  5. @Autowired
  6. private RoleMapper roleMapper;
  7. @Override
  8. public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
  9. //查数据库
  10. User user = userMapper.loadUserByUsername(userName);
  11. if (null != user) {
  12. List<Role> roles = roleMapper.getRolesByUserId(user.getId());
  13. user.setAuthorities(roles);
  14. }
  15. return user;
  16. }
  17. }

5.资源初始化

  1. @Component
  2. @Slf4j
  3. public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
  4. @Autowired
  5. private PermissionMapper permissionMapper;
  6. /**
  7. * 每一个资源所需要的角色 Collection<ConfigAttribute>决策器会用到
  8. */
  9. private static HashMap<String, Collection<ConfigAttribute>> map = null;
  10. /**
  11. * 返回请求的资源需要的角色
  12. */
  13. @Override
  14. public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
  15. //object 中包含用户请求的request 信息
  16. HttpServletRequest request = ((FilterInvocation) o).getHttpRequest();
  17. for (Iterator<String> it = map.keySet().iterator(); it.hasNext(); ) {
  18. String url = it.next();
  19. log.info("url==>{},request==>{}", url, request.getRequestURI());
  20. if (new AntPathRequestMatcher(url).matches(request)) {
  21. return map.get(url);
  22. }
  23. }
  24. return new ArrayList<>();
  25. }
  26. @Override
  27. public Collection<ConfigAttribute> getAllConfigAttributes() {
  28. //初始化 所有资源 对应的角色
  29. loadResourceDefine();
  30. return new ArrayList<>();
  31. }
  32. @Override
  33. public boolean supports(Class<?> aClass) {
  34. return true;
  35. }
  36. /**
  37. * 初始化 所有资源 对应的角色
  38. */
  39. public void loadResourceDefine() {
  40. map = new HashMap<>(16);
  41. //权限资源 和 角色对应的表 也就是 角色权限 中间表
  42. List<RolePermisson> rolePermissons = permissionMapper.getRolePermissions();
  43. //某个资源 可以被哪些角色访问
  44. for (RolePermisson rolePermisson : rolePermissons) {
  45. String url = rolePermisson.getUrl();
  46. String roleName = rolePermisson.getRoleName();
  47. ConfigAttribute role = new SecurityConfig(roleName);
  48. if (map.containsKey(url)) {
  49. map.get(url).add(role);
  50. } else {
  51. List<ConfigAttribute> list = new ArrayList<>();
  52. list.add(role);
  53. map.put(url, list);
  54. }
  55. }
  56. }
  57. }

6.决策器(也就是授权代码)

  1. /**
  2. * 决策器
  3. */
  4. @Component
  5. public class MyAccessDecisionManager implements AccessDecisionManager {
  6. /**
  7. * 通过传递的参数来决定用户是否有访问对应受保护对象的权限
  8. *
  9. * @param authentication 包含了当前的用户信息,包括拥有的权限。这里的权限来源就是前面登录时UserDetailsService中设置的authorities。
  10. * @param object 就是FilterInvocation对象,可以得到request等web资源
  11. * @param configAttributes configAttributes是本次访问需要的权限
  12. */
  13. @Override
  14. public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
  15. if (null == configAttributes || 0 >= configAttributes.size()) {
  16. return;
  17. } else {
  18. String needRole;
  19. for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
  20. needRole = iter.next().getAttribute();
  21. for(GrantedAuthority ga : authentication.getAuthorities()) {
  22. if(needRole.trim().equals(ga.getAuthority().trim())) {
  23. return;
  24. }
  25. }
  26. }
  27. throw new AccessDeniedException("当前访问没有权限");
  28. }
  29. }
  30. /**
  31. * 表示此AccessDecisionManager是否能够处理传递的ConfigAttribute呈现的授权请求
  32. */
  33. @Override
  34. public boolean supports(ConfigAttribute configAttribute) {
  35. return true;
  36. }
  37. /**
  38. * 表示当前AccessDecisionManager实现是否能够为指定的安全对象(方法调用或Web请求)提供访问控制决策
  39. */
  40. @Override
  41. public boolean supports(Class<?> aClass) {
  42. return true;
  43. }
  44. }

7.最后一步Security配置

  1. @Configuration
  2. @EnableWebSecurity
  3. @Slf4j
  4. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  5. @Autowired
  6. private MyUserDetailsService userService;
  7. @Autowired
  8. public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  9. //校验用户
  10. auth.userDetailsService(userService).passwordEncoder(new PasswordEncoder() {
  11. //对密码进行加密
  12. @Override
  13. public String encode(CharSequence charSequence) {
  14. log.info(charSequence.toString());
  15. return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
  16. }
  17. //对密码进行判断匹配
  18. @Override
  19. public boolean matches(CharSequence charSequence, String s) {
  20. String encode = DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
  21. boolean res = s.equals(encode);
  22. return res;
  23. }
  24. });
  25. }
  26. @Override
  27. protected void configure(HttpSecurity http) throws Exception {
  28. http.authorizeRequests()
  29. .antMatchers("/", "index", "/login", "/login-error", "/401", "/css/**", "/js/**").permitAll()
  30. .anyRequest().authenticated()
  31. .and()
  32. .formLogin().loginPage("/login").failureUrl("/login-error")
  33. .and()
  34. .exceptionHandling().accessDeniedPage("/401");
  35. http.logout().logoutSuccessUrl("/");
  36. }
  37. }

8.编写个控件器测试user用户和admin用户权限

  1. @Controller
  2. public class MainController {
  3. @RequestMapping("/")
  4. public String root() {
  5. return "redirect:/index";
  6. }
  7. @RequestMapping("/index")
  8. public String index() {
  9. return "index";
  10. }
  11. @RequestMapping("/login")
  12. public String login() {
  13. return "login";
  14. }
  15. @RequestMapping("/login-error")
  16. public String loginError(Model model) {
  17. model.addAttribute("loginError", true);
  18. return "login";
  19. }
  20. @GetMapping("/401")
  21. public String accessDenied() {
  22. return "401";
  23. }
  24. @GetMapping("/user/common")
  25. public String common() {
  26. return "user/common";
  27. }
  28. @GetMapping("/user/admin")
  29. public String admin() {
  30. return "user/admin";
  31. }
  32. }

资料

Spring Boot Security 保护你的程序的更多相关文章

  1. Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

    概要 之前的两篇文章,讲述了Spring Security 结合 OAuth2 .JWT 的使用,这一节要求对 OAuth2.JWT 有了解,若不清楚,先移步到下面两篇提前了解下. Spring Bo ...

  2. Spring Boot Security 整合 JWT 实现 无状态的分布式API接口

    简介 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案.JSON Web Token 入门教程 - 阮一峰,这篇文章可以帮你了解JWT的概念.本文重点讲解Spring Boo ...

  3. Spring Boot Security 整合 OAuth2 设计安全API接口服务

    简介 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版.本文重点讲解Spring Boot项目对OAuth2进行的实现,如果你对OAut ...

  4. Spring Boot Security配置教程

    1.简介 在本文中,我们将了解Spring Boot对spring Security的支持. 简而言之,我们将专注于默认Security配置以及如何在需要时禁用或自定义它. 2.默认Security设 ...

  5. Spring Boot Security Oauth2之客户端模式及密码模式实现

    Spring Boot Security Oauth2之客户端模式及密码模式实现 示例主要内容 1.多认证模式(密码模式.客户端模式) 2.token存到redis支持 3.资源保护 4.密码模式用户 ...

  6. boke练习: spring boot: security post数据时,要么关闭crst,要么添加隐藏域

    spring boot: security post数据时,要么关闭crst,要么添加隐藏域 http.csrf().disable(); 或者: <input name="${_cs ...

  7. Spring Boot Security And JSON Web Token

    Spring Boot Security And JSON Web Token 说明 流程说明 何时生成和使用jwt,其实我们主要是token更有意义并携带一些信息 https://github.co ...

  8. Spring Boot Security 使用教程

    虽然,我在实际项目中使用的是 shiro 进行权限管理,但 spring boot security 早已大名鼎鼎,虽然他的入门要相对复杂一点,但是设计视乎更加吸引人. 本章节就是以一篇快速入门 sp ...

  9. Spring Boot Security JWT 整合实现前后端分离认证示例

    前面两章节我们介绍了 Spring Boot Security 快速入门 和 Spring Boot JWT 快速入门,本章节使用 JWT 和 Spring Boot Security 构件一个前后端 ...

随机推荐

  1. Eclipse官方下载步骤

    今天整理Eclipse项目时,发现自己的IDE不能用了,不兼容自己的JDK,于是决定去官网下载一个适合的IDE,由于官网全部都是英文,所以不是太容易找到,于是就想着出一篇博客帮助以后的人更好的更快的下 ...

  2. vue中,使用element ui的弹窗与echarts之间的问题

    今天项目中有个需求,就是在页面中点击一个图标,弹出一个抽屉式的弹窗(弹窗是element UI的抽屉),弹窗里边是echarts呈现的数据,当我直接用echarts的时候,报错dom没有获取到: 这就 ...

  3. webpack4.0安装及使用(一)

    前言  1.什么是webpack 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建 ...

  4. 深入比特币原理(三)——交易的输入(input)与输出(output)

    本节内容非常重要,如果你不能很好的掌握本节内容,你无法真正理解比特币的运行原理,请务必要学习清楚. 比特币的交易模型为UTXO(unspend transaction output),即只记录未花费的 ...

  5. 使用react-breadcrumbs-dynamic

    这是完全独立于路由器的解决方案,你可以将其与任何版本的React Router(2或3或4)或任何其他用于React的路由库一起使用,或者完全不进行路由.您只需要指定面包屑项目及其道具的组件.然而道具 ...

  6. Spring MVC中的Controller是Serlvet吗?

    1. Controller不是Servlet DispatcherServler是Spring MVC中的唯一Servlet,(这点可通过查看FrameworkServlet的子类确认) Servle ...

  7. iOS App Extension入门

    转自简书:http://www.jianshu.com/p/8cf08db29356   iOS 10推出了很多新功能,其中有几个高调的变化:通知栏更加实用,电话可以防骚扰,iMessage变得更加有 ...

  8. [TimLinux] 命令 procps-ng 包内命令介绍

    1. procps-ng包 System and process monitoring utilities. 2. 文件列表 free, pgrep, pkill, pmap, ps, pwdx, s ...

  9. CapSupport 的使用

    CapSupport 是在CAP的操作上做了一些封装 目的是让事务同时执行或者同时回滚 startup services.AddCapSupport((optaion) => { optaion ...

  10. 【数据结构06】二叉平衡树(AVL树)

    目录 一.平衡二叉树定义 二.这货还是不是平衡二叉树? 三.平衡因子 四.如何保持平衡二叉树平衡? 五.平衡二叉树插入节点的四种情况 六.平衡二叉树操作的代码实现 七.AVL树总结 @ 一.平衡二叉树 ...