写在前面

在前面的学习当中,我们对spring security有了一个小小的认识,接下来我们整合目前的主流框架springBoot,实现权限的管理。

在这之前,假定你已经了解了基于资源的权限管理模型。数据库设计的表有 user 、role、user_role、permission、role_permission。

步骤:

默认大家都已经数据库已经好,已经有了上面提到的表。

第一步:在pom.xml文件中引入相关jar包

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.3.3.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>pers.lbf</groupId>
  12. <artifactId>springboot-spring-securioty-demo1</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>springboot-spring-security-demo1</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-security</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-web</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.mybatis.spring.boot</groupId>
  30. <artifactId>mybatis-spring-boot-starter</artifactId>
  31. <version>2.1.3</version>
  32. </dependency>
  33. <dependency>
  34. <groupId>mysql</groupId>
  35. <artifactId>mysql-connector-java</artifactId>
  36. <scope>runtime</scope>
  37. </dependency>
  38. <dependency>
  39. <groupId>org.springframework.boot</groupId>
  40. <artifactId>spring-boot-starter-test</artifactId>
  41. <scope>test</scope>
  42. <exclusions>
  43. <exclusion>
  44. <groupId>org.junit.vintage</groupId>
  45. <artifactId>junit-vintage-engine</artifactId>
  46. </exclusion>
  47. </exclusions>
  48. </dependency>
  49. <dependency>
  50. <groupId>org.springframework.security</groupId>
  51. <artifactId>spring-security-test</artifactId>
  52. <scope>test</scope>
  53. </dependency>
  54. </dependencies>
  55. <build>
  56. <plugins>
  57. <plugin>
  58. <groupId>org.springframework.boot</groupId>
  59. <artifactId>spring-boot-maven-plugin</artifactId>
  60. </plugin>
  61. </plugins>
  62. </build>
  63. </project>

第二步:修改application.yml文件,添加数据库相关配置

  1. server:
  2. port: 8081
  3. spring:
  4. datasource:
  5. url: jdbc:mysql://127.0.0.1:3306/secutiry_authority?useSSL=false&serverTimezone=GMT
  6. username: root
  7. password: root1997
  8. driver-class-name: com.mysql.cj.jdbc.Driver

第三步:启动项目

springboot已经给我们提供好了一个默认的username为“user”,其密码可以在控制台输出中得到。并且在springBoot的默认配置中,所有资源必须要通过认证后才能访问

打开<http://127.0.0.1:8081/login 即可看到默认的登录页面。

第四步:添加配置类,覆盖springBoot对spring security的默认配置

  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/8/28 20:22
  5. */
  6. @Configuration
  7. @EnableWebSecurity
  8. @EnableGlobalMethodSecurity(prePostEnabled = true)
  9. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  10. @Autowired
  11. private UserDetailsService userService;
  12. @Autowired
  13. private BCryptPasswordEncoder passwordEncoder;
  14. @Override
  15. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  16. auth.userDetailsService(userService).passwordEncoder(passwordEncoder);
  17. }
  18. @Override
  19. protected void configure(HttpSecurity http) throws Exception {
  20. //禁用跨域保护
  21. http.csrf().disable();
  22. //配置自定义登录页
  23. http.formLogin()
  24. .loginPage("/login.html")
  25. .loginProcessingUrl("/login")
  26. .defaultSuccessUrl("/")
  27. .usernameParameter("username")
  28. .passwordParameter("password");
  29. //配置登出
  30. http.logout()
  31. .logoutUrl("/logout")
  32. .logoutSuccessUrl("/login.html");
  33. }
  34. @Override
  35. public void configure(WebSecurity webSecurity) throws Exception{
  36. //忽略静态资源
  37. webSecurity.ignoring().antMatchers("/assents/**","/login.html");
  38. }
  39. }

第五步:编写代码,实现对User、role、permission的CRUD

5.1 编写自己的user对象,实现spring security的UserDetails接口,并实现对User的查找操作

关于为什么要实现这个接口,大家可以参考我上一篇文章《Spring Security认证流程分析--练气后期》。

  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/8/28 22:14
  5. */
  6. public class UserDO implements UserDetails {
  7. private Integer id;
  8. private String username;
  9. private String password;
  10. private Integer status;
  11. private List<SimpleGrantedAuthority> authorityList;
  12. @Override
  13. public String toString() {
  14. return "UserDO{" +
  15. "id=" + id +
  16. ", username='" + username + '\'' +
  17. ", password='" + password + '\'' +
  18. ", status=" + status +
  19. ", authorityList=" + authorityList +
  20. '}';
  21. }
  22. public List<SimpleGrantedAuthority> getAuthorityList() {
  23. return authorityList;
  24. }
  25. public void setAuthorityList(List<SimpleGrantedAuthority> authorityList) {
  26. this.authorityList = authorityList;
  27. }
  28. public void setUsername(String username) {
  29. this.username = username;
  30. }
  31. public void setPassword(String password) {
  32. this.password = password;
  33. }
  34. public int getStatus() {
  35. return status;
  36. }
  37. public void setStatus(int status) {
  38. this.status = status;
  39. }
  40. public Integer getId() {
  41. return id;
  42. }
  43. public void setId(Integer id) {
  44. this.id = id;
  45. }
  46. public void setStatus(Integer status) {
  47. this.status = status;
  48. }
  49. /**
  50. * Returns the authorities granted to the user. Cannot return <code>null</code>.
  51. *
  52. * @return the authorities, sorted by natural key (never <code>null</code>)
  53. */
  54. @Override
  55. public Collection<? extends GrantedAuthority> getAuthorities() {
  56. return this.authorityList;
  57. }
  58. /**
  59. * Returns the password used to authenticate the user.
  60. *
  61. * @return the password
  62. */
  63. @Override
  64. public String getPassword() {
  65. return this.password;
  66. }
  67. /**
  68. * Returns the username used to authenticate the user. Cannot return <code>null</code>.
  69. *
  70. * @return the username (never <code>null</code>)
  71. */
  72. @Override
  73. public String getUsername() {
  74. return this.username;
  75. }
  76. /**
  77. * Indicates whether the user's account has expired. An expired account cannot be
  78. * authenticated.
  79. *
  80. * @return <code>true</code> if the user's account is valid (ie non-expired),
  81. * <code>false</code> if no longer valid (ie expired)
  82. */
  83. @Override
  84. public boolean isAccountNonExpired() {
  85. return this.status==1;
  86. }
  87. /**
  88. * Indicates whether the user is locked or unlocked. A locked user cannot be
  89. * authenticated.
  90. *
  91. * @return <code>true</code> if the user is not locked, <code>false</code> otherwise
  92. */
  93. @Override
  94. public boolean isAccountNonLocked() {
  95. return this.status == 1;
  96. }
  97. /**
  98. * Indicates whether the user's credentials (password) has expired. Expired
  99. * credentials prevent authentication.
  100. *
  101. * @return <code>true</code> if the user's credentials are valid (ie non-expired),
  102. * <code>false</code> if no longer valid (ie expired)
  103. */
  104. @Override
  105. public boolean isCredentialsNonExpired() {
  106. return true;
  107. }
  108. /**
  109. * Indicates whether the user is enabled or disabled. A disabled user cannot be
  110. * authenticated.
  111. *
  112. * @return <code>true</code> if the user is enabled, <code>false</code> otherwise
  113. */
  114. @Override
  115. public boolean isEnabled() {
  116. return this.status==1;
  117. }
  118. }

关于用户凭证是否过期、账户是否被锁定大家可以自己实现一下

  1. **
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/8/28 22:17
  5. */
  6. public interface IUserDao {
  7. @Select("select * from sys_user u where u.username=#{name}")
  8. UserDO findByName(String name);
  9. }

5.2 编写Role和Permission两个实体类,并实现对其查找的Dao

RoleDO

  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/9/1 20:51
  5. */
  6. public class RoleDO implements Serializable {
  7. private Integer id;
  8. private String roleName;
  9. private String roleDesc;
  10. }

PermissionDO

  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/9/1 21:27
  5. */
  6. public class PermissionDO implements Serializable {
  7. private Integer id;
  8. private String permissionName;
  9. private String permissionUrl;
  10. private Integer parentId;
  11. }

IRoleDao

  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/9/1 20:53
  5. */
  6. public interface IRoleDao {
  7. @Select("select * from sys_role sr where sr.id in (select rid from sys_user_role where uid=#{userId})")
  8. List<RoleDO> findByUserId(Integer userId);
  9. }

IPermissionDao

  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/9/1 21:30
  5. */
  6. public interface IPermissonDao {
  7. @Select("select * from sys_permission sp where sp.id in (select pid from sys_role_permission where rid=#{roleId})")
  8. List<PermissionDO> findByRoleId(Integer roleId);
  9. }

5.3 编写UserService 实现UserDetailsService接口并实现loadUserByUsername方法

  1. **
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/8/28 22:16
  5. */
  6. @Service("userService")
  7. public class UserServiceImpl implements UserDetailsService {
  8. @Autowired
  9. private IUserDao userDao;
  10. @Autowired
  11. private IRoleDao roleDao;
  12. @Autowired
  13. private IPermissonDao permissonDao;
  14. @Override
  15. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  16. if (username == null){
  17. return null;
  18. }
  19. UserDO user = userDao.findByName(username);
  20. //加载权限
  21. List<RoleDO> roleList = roleDao.findByUserId(user.getId());
  22. List<SimpleGrantedAuthority> list = new ArrayList<> ();
  23. for (RoleDO roleDO : roleList) {
  24. List<PermissionDO> permissionListItems = permissonDao.findByRoleId(roleDO.getId());
  25. for (PermissionDO permissionDO : permissionListItems) {
  26. list.add(new SimpleGrantedAuthority(permissionDO.getPermissionUrl()));
  27. }
  28. }
  29. user.setAuthorityList(list);
  30. return user;
  31. }
  32. }

第六步:编写一个测试接口

  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/8/27 20:02
  5. */
  6. @RestController
  7. @RequestMapping("/product")
  8. public class TestController {
  9. @GetMapping("/")
  10. @PreAuthorize("hasAuthority('product:get')")
  11. public String get() {
  12. return "调用成功";
  13. }
  14. }

第七步 :使用postman进行测试

7.1登录操作

登录成果返回主页

登录失败返回登录页面

7.2调用受保护的接口

有权限则调用成功

无权限返回403

大家可以实现一下对异常的拦截,给用户返回一个友好的提示。

写在最后

这是springBoot整合spring security单体应用的一个小demo。关于分布式的、使用JWT代替spring security 的csrf,并自定义认证器的例子将在我的下一篇文章中介绍。

代码及sql脚本下载:https://github.com/code81192/art-demo/tree/master/springboot-spring-securioty-demo1

springBoot整合spring security实现权限管理(单体应用版)--筑基初期的更多相关文章

  1. springBoot整合spring security+JWT实现单点登录与权限管理--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  2. SpringBoot整合Spring Security

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Securi ...

  3. 使用Spring Security实现权限管理

    使用Spring Security实现权限管理 1.技术目标 了解并创建Security框架所需数据表 为项目添加Spring Security框架 掌握Security框架配置 应用Security ...

  4. SpringBoot 整合Spring Security框架

    引入maven依赖 <!-- 放入spring security依赖 --> <dependency> <groupId>org.springframework.b ...

  5. SpringBoot整合Spring Security使用Demo

    https://start.spring.io/ 生成SpringBoot项目 pom文件应该是我这样的: <?xml version="1.0" encoding=&quo ...

  6. SpringBoot 整合 spring security oauth2 jwt完整示例 附源码

    废话不说直接进入主题(假设您已对spring security.oauth2.jwt技术的了解,不懂的自行搜索了解) 依赖版本 springboot 2.1.5.RELEASE spring-secu ...

  7. springboot配置spring security 静态资源不能访问

    在springboot整合spring security 过程中曾遇到下面问题:(spring boot 2.0以上版本   spring security 5.x    (spring  secur ...

  8. SpringBoot安全篇Ⅵ --- 整合Spring Security

    知识储备: 关于SpringSecurity的详细学习可以查看SpringSecurity的官方文档. Spring Security概览 应用程序的两个主要区域是"认证"和&qu ...

  9. springboot+maven整合spring security

    springboot+maven整合spring security已经做了两次了,然而还是不太熟悉,这里针对后台简单记录一下需要做哪些事情,具体的步骤怎么操作网上都有,不再赘述.1.pom.xml中添 ...

随机推荐

  1. VS c# 操作 Microsoft Project mpp 文件 并遍历边关系

    网上找到资料提供了遍历.mpp文件中任务的功能: http://blog.csdn.net/gxf36/article/details/5253792 ======================== ...

  2. SeaweedFS在.net core下的实践方案

    一直对分布式的文件储存系统很感兴趣,最开始关注淘宝的TFS(Taobao File System),好像搁浅了,官方地址无法访问,github上面,各种编译问题,无意间发现了SeaweedFS 链接s ...

  3. 【SDOI2012】Longge 的问题 题解(欧拉函数)

    前言:还算比较简单的数学题,我这种数学蒟蒻也会做QAQ. --------------- 题意:求$\sum\limits_{i=1}^n gcd(i,n)$的值. 设$gcd(i,n)=d$,即$d ...

  4. 28-关键字:static

    static:静态的 1.可以用来修饰的结构:主要用来修饰类的内部结构 >属性.方法.代码块.内部类 2.static修饰属性:静态变量(或类变量) 2.1 属性,是否使用static修饰,又分 ...

  5. JSP中contentType、pageEncoding和meta charset的区别

    1.创建JSP 使用Eclipse创建JSP文件: <%@ page language="java" contentType="text/html; charset ...

  6. 算法学习笔记:2-SAT

    SAT 是适定性(Satisfiability)问题的简称.一般形式为 k - 适定性问题,简称 k-SAT.而当 \(k>2\) 时该问题为 NP 完全的.所以我们只研究 \(k=2\) 的情 ...

  7. 商品描述(动画)--- jQuery

    本文章实现是基于jQuery展示商品描述的一个功能 (1)鼠标移入显示描述内容,鼠标移开内容隐藏.先来看看一个先后效果. (2)jQuery所以的文件可以自行下载,也可以在我主页找到文件,右键文件名复 ...

  8. RabbitMQ 基础概念进阶

    上一篇 RabbitMQ 入门之基础概念 介绍了 RabbitMQ 的一些基础概念,本文再来介绍其中的一些细节和其它的进阶的概念. 一.消息生产者发送的消息不可达时如何处理 RabbitMQ 提供了消 ...

  9. JVM初探(五):类的实例化

    一.概述 我们知道,一个对象在可以被使用之前必须要被正确地实例化.而实例化实际指的就是以一个java类为模板创建对象/实例的过程.比如说常见的 Person = new Person()代码就是一个将 ...

  10. C#设计模式之11-享元模式

    享元模式(Flyweight Pattern) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/409 访问. 享元模式属 ...