写在前面

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

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

步骤:

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

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

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>pers.lbf</groupId>
<artifactId>springboot-spring-securioty-demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-spring-security-demo1</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <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.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

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

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

第三步:启动项目

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

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

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

/**
* @author 赖柄沣 bingfengdev@aliyun.com
* @version 1.0
* @date 2020/8/28 20:22
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired
private UserDetailsService userService; @Autowired
private BCryptPasswordEncoder passwordEncoder; @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder);
} @Override
protected void configure(HttpSecurity http) throws Exception { //禁用跨域保护
http.csrf().disable(); //配置自定义登录页
http.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/")
.usernameParameter("username")
.passwordParameter("password"); //配置登出
http.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login.html"); } @Override
public void configure(WebSecurity webSecurity) throws Exception{
//忽略静态资源
webSecurity.ignoring().antMatchers("/assents/**","/login.html");
} }

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

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

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

/**
* @author 赖柄沣 bingfengdev@aliyun.com
* @version 1.0
* @date 2020/8/28 22:14
*/
public class UserDO implements UserDetails { private Integer id;
private String username;
private String password;
private Integer status;
private List<SimpleGrantedAuthority> authorityList; @Override
public String toString() {
return "UserDO{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", status=" + status +
", authorityList=" + authorityList +
'}';
} public List<SimpleGrantedAuthority> getAuthorityList() {
return authorityList;
} public void setAuthorityList(List<SimpleGrantedAuthority> authorityList) {
this.authorityList = authorityList;
} public void setUsername(String username) {
this.username = username;
} public void setPassword(String password) {
this.password = password;
} public int getStatus() {
return status;
} public void setStatus(int status) {
this.status = status;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public void setStatus(Integer status) {
this.status = status;
} /**
* Returns the authorities granted to the user. Cannot return <code>null</code>.
*
* @return the authorities, sorted by natural key (never <code>null</code>)
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() { return this.authorityList;
} /**
* Returns the password used to authenticate the user.
*
* @return the password
*/
@Override
public String getPassword() {
return this.password;
} /**
* Returns the username used to authenticate the user. Cannot return <code>null</code>.
*
* @return the username (never <code>null</code>)
*/
@Override
public String getUsername() {
return this.username;
} /**
* Indicates whether the user's account has expired. An expired account cannot be
* authenticated.
*
* @return <code>true</code> if the user's account is valid (ie non-expired),
* <code>false</code> if no longer valid (ie expired)
*/
@Override
public boolean isAccountNonExpired() {
return this.status==1;
} /**
* Indicates whether the user is locked or unlocked. A locked user cannot be
* authenticated.
*
* @return <code>true</code> if the user is not locked, <code>false</code> otherwise
*/
@Override
public boolean isAccountNonLocked() {
return this.status == 1;
} /**
* Indicates whether the user's credentials (password) has expired. Expired
* credentials prevent authentication.
*
* @return <code>true</code> if the user's credentials are valid (ie non-expired),
* <code>false</code> if no longer valid (ie expired)
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
} /**
* Indicates whether the user is enabled or disabled. A disabled user cannot be
* authenticated.
*
* @return <code>true</code> if the user is enabled, <code>false</code> otherwise
*/
@Override
public boolean isEnabled() {
return this.status==1;
}
}

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

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

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

RoleDO

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

PermissionDO

/**
* @author 赖柄沣 bingfengdev@aliyun.com
* @version 1.0
* @date 2020/9/1 21:27
*/
public class PermissionDO implements Serializable {
private Integer id;
private String permissionName;
private String permissionUrl;
private Integer parentId; }

IRoleDao

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

IPermissionDao

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

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

**
* @author 赖柄沣 bingfengdev@aliyun.com
* @version 1.0
* @date 2020/8/28 22:16
*/
@Service("userService")
public class UserServiceImpl implements UserDetailsService { @Autowired
private IUserDao userDao;
@Autowired
private IRoleDao roleDao;
@Autowired
private IPermissonDao permissonDao; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username == null){
return null;
} UserDO user = userDao.findByName(username);
//加载权限
List<RoleDO> roleList = roleDao.findByUserId(user.getId()); List<SimpleGrantedAuthority> list = new ArrayList<> ();
for (RoleDO roleDO : roleList) {
List<PermissionDO> permissionListItems = permissonDao.findByRoleId(roleDO.getId());
for (PermissionDO permissionDO : permissionListItems) {
list.add(new SimpleGrantedAuthority(permissionDO.getPermissionUrl()));
}
}
user.setAuthorityList(list); return user;
}
}

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

/**
* @author 赖柄沣 bingfengdev@aliyun.com
* @version 1.0
* @date 2020/8/27 20:02
*/
@RestController
@RequestMapping("/product")
public class TestController { @GetMapping("/")
@PreAuthorize("hasAuthority('product:get')")
public String get() {
return "调用成功";
}
}

第七步 :使用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. 服务没有报告任何错误。 请键入 NET HELPMSG 3534 以获得更多的帮助。

    解决: 删除data文件夹 然后按顺序执行: sc delete mysql mysqld  --initialize-insecure mysqld -install mysql net start ...

  2. vue_shop(基于vue电商管理后台网站)

    vue_shop 目录 vue_shop day01 实现登录功能 项目预开发处理 Login.vue完整代码: 处理步骤: 添加element-ui的表单组件 添加第三方字体: 添加表单验证 导入a ...

  3. python与pycharm的爱恨情仇

    首先大家应该区别 这两者是什么? python 是一门语言 pycharm 是工具 还得交待的是  可以编译python的工具 不止这一款 比如说--eclipse idea ... eclipse中 ...

  4. .net core编写转发服务(二) 添加服务发布订阅

    源设计就单纯完成了把服务转发到特定的服务模块,一定程度上解耦了业务流程 但是我们实际开发过程中会面临服务转发后还有一些列关联的服务 举个例子 你调用了发送邮件的服务,接下来会面临扣费的服务,扣费之后会 ...

  5. 22-关键字:super

    1.super 关键字可以理解为:父类的 2.可以用来调用的结构: 属性.方法.构造器 3.super调用属性.方法: 3.1 我们可以在子类的方法或构造器中.通过使用"super.属性&q ...

  6. Linux系统中玩到让你停不下来的命令行游戏!

    大家好,我是良许. 在使用 Linux 系统时,命令行不仅可以让我们在工作中提高效率,它还可以在生活上给我们提供各种娱乐活动,因为你可以使用它玩许多非常有意思的游戏,这些游戏可都不需要使用专用显卡. ...

  7. java 静态导入、可变参数、集合嵌套

    一 静态导入 在导包的过程中我们可以直接导入静态部分,这样某个类的静态成员就可以直接使用了. 在源码中经常会出现静态导入. 静态导入格式: import static XXX.YYY;   导入后YY ...

  8. Jdk1.7下的HashMap源码分析

    本文主要讨论jdk1.7下hashMap的源码实现,其中主要是在扩容时容易出现死循环的问题,以及put元素的整个过程. 1.数组结构 数组+链表 示例图如下: 常量属性 /** * The defau ...

  9. excel如何写宏?如何用按钮?

    注:本次测试版本 excel版本2019 写宏? 准备工作(使用宏的一切前提)===========文件-选项-自定义功能区 (勾选开发工具) 开始写宏=======右击sheet1--查看代码    ...

  10. C#/VB.NET 比较两个Word文档差异

    本文以C#和VB.NET代码为例,来介绍如何对比两个Word文档差异.程序中使用最新版的Spire.Doc for .NET 版本8.8.2.编辑代码前,先在VS程序中添加引用Spire.Doc.dl ...