因为项目需要,第一次接触 Spring Security,早就听闻 Spring Security 功能强大但上手困难,学习了几天出入门道,特整理这篇文章希望能让后来者少踩一点坑(本文附带实例程序,请放心食用

本篇文章环境:SpringBoot 2.0 + Mybatis + Spring Security 5.0

源码地址:https://github.com/jitwxs/blog_sample

文章目录

一、导入依赖
二、创建数据库
三、准备页面
四、配置application.properties
五、创建实体、Dao、Service和Controller
  5.1 实体
  5.2 Dao
  5.3 Service
  5.4 Controller
六、配置SpringSecurity
  6.1 UserDetailsService
  6.2 WebSecurityConfig
七、运行程序

一、导入依赖

导入 spring-boot-starter-security 依赖,在 SpringBoot 2.0 环境下默认使用的是 5.0 版本。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> <dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

二、创建数据库

一般权限控制有三层,即:用户<–>角色<–>权限,用户与角色是多对多,角色和权限也是多对多。这里我们先暂时不考虑权限,只考虑用户<–>角色

创建用户表sys_user

CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建权限表sys_role

CREATE TABLE `sys_role` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建用户-角色表sys_user_role

CREATE TABLE `sys_user_role` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`role_id`),
KEY `fk_role_id` (`role_id`),
CONSTRAINT `fk_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

初始化一下数据:

INSERT INTO `sys_role` VALUES ('', 'ROLE_ADMIN');
INSERT INTO `sys_role` VALUES ('', 'ROLE_USER'); INSERT INTO `sys_user` VALUES ('', 'admin', '');
INSERT INTO `sys_user` VALUES ('', 'jitwxs', ''); INSERT INTO `sys_user_role` VALUES ('', '');
INSERT INTO `sys_user_role` VALUES ('', '');

博主有话说:

这里的权限格式为ROLE_XXX,是Spring Security规定的,不要乱起名字哦。

三、准备页面

因为是示例程序,页面越简单越好,只用于登陆的login.html以及用于登陆成功后的home.html,将其放置在 resources/static 目录下:

(1)login.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆</title>
</head>
<body>
<h1>登陆</h1>
<form method="post" action="/login">
<div>
用户名:<input type="text" name="username">
</div>
<div>
密码:<input type="password" name="password">
</div>
<div>
<button type="submit">立即登陆</button>
</div>
</form>
</body>
</html>

博主有话说:

用户的登陆认证是由Spring Security进行处理的,请求路径默认为/login,用户名字段默认为username,密码字段默认为password

(2)home.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登陆成功</h1>
<a href="/admin">检测ROLE_ADMIN角色</a>
<a href="/user">检测ROLE_USER角色</a>
<button onclick="window.location.href='/logout'">退出登录</button>
</body>
</html>

四、配置application.properties

在配置文件中配置下数据库连接:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
spring.datasource.username=root
spring.datasource.password=root #开启Mybatis下划线命名转驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true

五、创建实体、Dao、Service和Controller

5.1 实体

(1)SysUser

public class SysUser implements Serializable{
static final long serialVersionUID = 1L; private Integer id; private String name; private String password; // 省略getter/setter
}

(2)SysRole

public class SysRole implements Serializable {
static final long serialVersionUID = 1L; private Integer id; private String name; // 省略getter/setter
}

(3)SysUserRole

public class SysUserRole implements Serializable {
static final long serialVersionUID = 1L; private Integer userId; private Integer roleId; // 省略getter/setter
}

5.2 Dao

(1)SysUserMapper

@Mapper
public interface SysUserMapper {
@Select("SELECT * FROM sys_user WHERE id = #{id}")
SysUser selectById(Integer id); @Select("SELECT * FROM sys_user WHERE name = #{name}")
SysUser selectByName(String name);
}

(2)SysRoleMapper

@Mapper
public interface SysRoleMapper {
@Select("SELECT * FROM sys_role WHERE id = #{id}")
SysRole selectById(Integer id);
}

(3)SysUserRoleMapper

@Mapper
public interface SysUserRoleMapper {
@Select("SELECT * FROM sys_user_role WHERE user_id = #{userId}")
List<SysUserRole> listByUserId(Integer userId);
}

5.3 Service

(1)SysUserService

@Service
public class SysUserService {
@Autowired
private SysUserMapper userMapper; public SysUser selectById(Integer id) {
return userMapper.selectById(id);
} public SysUser selectByName(String name) {
return userMapper.selectByName(name);
}
}

(2)SysRoleService

@Service
public class SysRoleService {
@Autowired
private SysRoleMapper roleMapper; public SysRole selectById(Integer id){
return roleMapper.selectById(id);
}
}

(3)SysUserRoleService

@Service
public class SysUserRoleService {
@Autowired
private SysUserRoleMapper userRoleMapper; public List<SysUserRole> listByUserId(Integer userId) {
return userRoleMapper.listByUserId(userId);
}
}

5.4 Controller

@Controller
public class LoginController {
private Logger logger = LoggerFactory.getLogger(LoginController.class); @RequestMapping("/")
public String showHome() {
String name = SecurityContextHolder.getContext().getAuthentication().getName();
logger.info("当前登陆用户:" + name); return "home.html";
} @RequestMapping("/login")
public String showLogin() {
return "login.html";
} @RequestMapping("/admin")
@ResponseBody
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String printAdmin() {
return "如果你看见这句话,说明你有ROLE_ADMIN角色";
} @RequestMapping("/user")
@ResponseBody
@PreAuthorize("hasRole('ROLE_USER')")
public String printUser() {
return "如果你看见这句话,说明你有ROLE_USER角色";
}
}

博主有话说:

  • 如代码所示,获取当前登录用户:SecurityContextHolder.getContext().getAuthentication()

  • @PreAuthorize 用于判断用户是否有指定权限,没有就不能访问

六、配置SpringSecurity

6.1 UserDetailsService

首先我们需要自定义 UserDetailsService ,将用户信息和权限注入进来。

我们需要重写 loadUserByUsername 方法,参数是用户输入的用户名。返回值是UserDetails,这是一个接口,一般使用它的子类org.springframework.security.core.userdetails.User,它有三个参数,分别是用户名、密码和权限集。

实际情况下,大多将 DAO 中的 User 类继承 org.springframework.security.core.userdetails.User 返回。

@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private SysUserService userService; @Autowired
private SysRoleService roleService; @Autowired
private SysUserRoleService userRoleService; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
// 从数据库中取出用户信息
SysUser user = userService.selectByName(username); // 判断用户是否存在
if(user == null) {
throw new UsernameNotFoundException("用户名不存在");
} // 添加权限
List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId());
for (SysUserRole userRole : userRoles) {
SysRole role = roleService.selectById(userRole.getRoleId());
authorities.add(new SimpleGrantedAuthority(role.getName()));
} // 返回UserDetails实现类
return new User(user.getName(), user.getPassword(), authorities);
}
}

6.2 WebSecurityConfig

该类是 Spring Security 的配置类,该类的三个注解分别是标识该类是配置类、开启 Security 服务、开启全局 Securtiy 注解。

首先将我们自定义的 userDetailsService 注入进来,在 configure() 方法中使用 auth.userDetailsService() 方法替换掉默认的 userDetailsService。

这里我们还指定了密码的加密方式(5.0 版本强制要求设置),因为我们数据库是明文存储的,所以明文返回即可,如下所示:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService; @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
} @Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
});
} @Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 如果有允许匿名的url,填在下面
// .antMatchers().permitAll()
.anyRequest().authenticated()
.and()
// 设置登陆页
.formLogin().loginPage("/login")
// 设置登陆成功页
.defaultSuccessUrl("/").permitAll()
// 自定义登陆用户名和密码参数,默认为username和password
// .usernameParameter("username")
// .passwordParameter("password")
.and()
.logout().permitAll(); // 关闭CSRF跨域
http.csrf().disable();
} @Override
public void configure(WebSecurity web) throws Exception {
// 设置拦截忽略文件夹,可以对静态资源放行
web.ignoring().antMatchers("/css/**", "/js/**");
}
}

七、运行程序

注:如果你想要将密码加密,可以修改 configure() 方法如下:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}

---------------------

作者:Jitwxs
来源:CSDN
原文:https://blog.csdn.net/yuanlaijike/article/details/80249235

SpringBoot集成Spring Security(1)——入门程序的更多相关文章

  1. SpringBoot集成Spring Security入门体验

    一.前言 Spring Security 和 Apache Shiro 都是安全框架,为Java应用程序提供身份认证和授权. 二者区别 Spring Security:重量级安全框架 Apache S ...

  2. SpringBoot集成Spring Security(6)——登录管理

    文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...

  3. SpringBoot集成Spring Security(2)——自动登录

    在上一章:SpringBoot集成Spring Security(1)——入门程序中,我们实现了入门程序,本篇为该程序加上自动登录的功能. 文章目录 一.修改login.html二.两种实现方式 2. ...

  4. SpringBoot集成Spring Security(5)——权限控制

    在第一篇中,我们说过,用户<–>角色<–>权限三层中,暂时不考虑权限,在这一篇,是时候把它完成了. 为了方便演示,这里的权限只是对角色赋予权限,也就是说同一个角色的用户,权限是 ...

  5. SpringBoot集成Spring Security(4)——自定义表单登录

    通过前面三篇文章,你应该大致了解了 Spring Security 的流程.你应该发现了,真正的 login 请求是由 Spring Security 帮我们处理的,那么我们如何实现自定义表单登录呢, ...

  6. SpringBoot集成Spring Security(7)——认证流程

    文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...

  7. springboot集成spring security安全框架入门篇

    一. :spring security的简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下 ...

  8. SpringBoot集成Spring Security

    1.Spring Security介绍 Spring security,是一个强大的和高度可定制的身份验证和访问控制框架.它是确保基于Spring的应用程序的标准 --来自官方参考手册 Spring ...

  9. SpringBoot 集成Spring security

    Spring security作为一种安全框架,使用简单,能够很轻松的集成到springboot项目中,下面讲一下如何在SpringBoot中集成Spring Security.使用gradle项目管 ...

随机推荐

  1. Mysql设置binlog过期时间并自动删除

    问题: Mysql数据库由于业务原因,数据量增长迅速,binlog日志会增加较多,占用大部分磁盘空间. 解决方案: 出于节约空间考虑,可进行删除多余binary日志,并设置定期删除操作. .查看bin ...

  2. 单独KafkaConsumer实例and多worker线程。

    1.单独KafkaConsumer实例and多worker线程.将获取的消息和消息的处理解耦,将消息的处理放入单独的工作者线程中,即工作线程中,同时维护一个或者若各干consumer实例执行消息获取任 ...

  3. Unity音乐喷泉效果

    本文参考了该文,其素材也取之于该处 效果 实现效果(根据音乐的高低会产生不同的波纹): 可以观看视频来获得更好的体验. 波纹的实现 先模拟出如下效果: 通过鼠标的点击,产生一个扩散的圆圈. 如上图所示 ...

  4. afnetwork使用

    Usage HTTP Request Operation Manager AFHTTPRequestOperationManager encapsulates the common patterns ...

  5. Fundebug录屏插件更新至0.5.0,新增domain参数

    摘要: 通过配置domain来保证"视频"的正确录制 录屏功能介绍 Fundebug提供专业的异常监控服务,当线上应用出现 BUG 的时候,我们可以第一时间报警,帮助开发者及时发现 ...

  6. [TCP/IP] TCP在listen时的参数backlog的意义

    linux内核中会维护两个队列:  1)未完成队列:接收到一个SYN建立连接请求,处于SYN_RCVD状态  2)已完成队列:已完成TCP三次握手过程,处于ESTABLISHED状态  3)当有一个S ...

  7. 10wx.showToast消息提示框 wx.showModal模态对话框

    1==>wx.showToast 弹出层 在界面交互中 显示消息提示框 它是一个消失提示框 提示用户成功 或者失败等消息 <button size='mini' bindtap='hanl ...

  8. luoguP1195 口袋的天空

    生成树一 题目描述 给你云朵的个数NN,再给你MM个关系,表示哪些云朵可以连在一起. 现在小杉要把所有云朵连成KK个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小. 链接 分析 ...

  9. appium连接genymation运行计算器的例子

    #coding=utf-8from appium import webdriverdesired_caps={}desired_caps["platformName"]=" ...

  10. shell 之for循环几种写法

    参见博客 http://blog.csdn.net/babyfish13/article/details/52981110 ,此博客写的非常清晰明了.