1. 简介

  Spring Security是一个功能强大且易于扩展的安全框架,主要用于为Java程序提供用户认证(Authentication)和用户授权(Authorization)功能。

  本文将之前博客 SpringBoot2.x集成Quartz实现定时任务管理(持久化到数据库) 改为使用Spring Security进行统一的认证和授权。除了将登录使用Spring Security管理之外,还增加了角色管理、权限管理等菜单,并对系统的权限进行更加细颗粒度的管理和鉴权,使得系统更加安全,便于和其他系统单点集成。

2. Spring Security相关博客(推荐)

  SpringBoot + SpringSecurity + Mybatis-Plus + JWT实现分布式系统认证和授权

  SpringBoot + SpringSecurity + Mybatis-Plus + JWT + Redis 实现分布式系统认证和授权(刷新Token和Token黑名单)

3. 前期回顾(时间升序)

  SpringBoot + Layui +Mybatis-plus实现简单后台管理系统(内置安全过滤器)

  SpringBoot基于JustAuth实现第三方授权登录

  SpringBoot + Layui + JustAuth +Mybatis-plus实现可第三方登录的简单后台管理系统

  SpringBoot2.x集成Quartz实现定时任务管理(持久化到数据库)

4. 初始化数据库

  在之前数据库上增加四张表,分别为:

-- ----------------------------
-- Table structure for t_sys_auth
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_auth`;
CREATE TABLE `t_sys_auth` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`auth_name` varchar(50) NOT NULL COMMENT '权限名称',
`permission` varchar(200) NULL DEFAULT NULL COMMENT '权限标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '系统权限'; -- ----------------------------
-- Table structure for t_sys_role
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role`;
CREATE TABLE `t_sys_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role_name` varchar(50) NULL DEFAULT NULL COMMENT '角色名称',
`role_code` varchar(50) NOT NULL COMMENT '角色编码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '系统角色'; -- ----------------------------
-- Table structure for t_sys_role_auth
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role_auth`;
CREATE TABLE `t_sys_role_auth` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
`auth_id` bigint(20) NULL DEFAULT NULL COMMENT '权限ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '角色权限关系'; -- ----------------------------
-- Table structure for t_sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user_role`;
CREATE TABLE `t_sys_user_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
`role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '用户角色关系';

完整的初始化数据库脚本在项目源码的db文件夹

5. 代码迭代

  • 修改pom.xml,增加Spring Security依赖
<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>
<groupId>com.c3stones</groupId>
<artifactId>spring-security-quartz-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-quartz-demo</name>
<description>Spring Security Quartz Demo</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.8.RELEASE</version>
<relativePath />
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<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>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
  • 增加刚刚添加的四张表对应的实体、Mapper、Service及Service实现类

      以表t_sys_role为例,增加系统角色实体等类,其他请参考系统角色自行添加。
import java.io.Serializable;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data;
import lombok.EqualsAndHashCode; /**
* 系统角色
*
* @author CL
*
*/
@Data
@TableName("t_sys_role")
@EqualsAndHashCode(callSuper = false)
public class Role extends Model<Role> implements Serializable {
private static final long serialVersionUID = 1L; /**
* 角色ID
*/
@TableId(type = IdType.AUTO)
private Integer id; /**
* 角色名称
*/
private String roleName; /**
* 角色编码
*/
private String roleCode; }
import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.c3stones.sys.entity.Role; /**
* 系统角色Mapper
*
* @author CL
*
*/
@Mapper
public interface RoleMapper extends BaseMapper<Role> { }
import java.util.List;

import javax.validation.constraints.NotNull;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.c3stones.sys.entity.Role;
import com.c3stones.sys.entity.User;
import com.c3stones.sys.entity.UserRole; /**
* 系统角色Service
*
* @author CL
*
*/
public interface RoleService extends IService<Role> { }
import java.util.List;
import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.ListUtils; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.c3stones.sys.entity.Role;
import com.c3stones.sys.entity.User;
import com.c3stones.sys.entity.UserRole;
import com.c3stones.sys.mapper.RoleMapper;
import com.c3stones.sys.mapper.UserMapper;
import com.c3stones.sys.mapper.UserRoleMapper;
import com.c3stones.sys.service.RoleService; import cn.hutool.core.util.StrUtil; /**
* 系统角色Service实现
*
* @author CL
*
*/
@Service
public class RoleSerivceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
}
  • 增加用户详情实体,用于系统上下文之间传递用户信息
import java.io.Serializable;
import java.util.Collection; import org.springframework.security.core.GrantedAuthority; import com.c3stones.sys.entity.User; import lombok.Data;
import lombok.EqualsAndHashCode; /**
* 系统用户详情
*
* @author CL
*
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class UserDetails extends User
implements org.springframework.security.core.userdetails.UserDetails, Serializable {
private static final long serialVersionUID = 1L; /**
* 用户角色
*/
private Collection<GrantedAuthority> authorities; /**
* 账号是否过期
*/
private boolean isAccountNonExpired = false; /**
* 账号是否锁定
*/
private boolean isAccountNonLocked = false; /**
* 证书是否过期
*/
private boolean isCredentialsNonExpired = false; /**
* 账号是否有效
*/
private boolean isEnabled = true; /**
* 获得用户权限
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
} /**
* 判断账号是否过期
*/
@Override
public boolean isAccountNonExpired() {
return isAccountNonExpired;
} /**
* 判断账号是否锁定
*/
@Override
public boolean isAccountNonLocked() {
return isAccountNonLocked;
} /**
* 判断证书是否过期
*/
@Override
public boolean isCredentialsNonExpired() {
return isCredentialsNonExpired;
} /**
* 判断账号是否有效
*/
@Override
public boolean isEnabled() {
return isEnabled;
} }
  • 增加用户详情Service,用于系统登录认证和获取用户角色等信息

      需要添加的基础的用户、角色、权限等方法(如查询用户角色、角色权限等方法),请下载项目源码查看。
import java.util.HashSet;
import java.util.List;
import java.util.Set; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.c3stones.security.entity.UserDetails;
import com.c3stones.sys.entity.Role;
import com.c3stones.sys.entity.User;
import com.c3stones.sys.service.RoleService;
import com.c3stones.sys.service.UserService; /**
* 用户登录Service
*
* @author CL
*
*/
@Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService { @Autowired
private UserService userService; @Autowired
private RoleService roleService; /**
* 根据用户名查用户信息
*
* @param username 用户名称
* @return 用户详细信息
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
User user = userService.getOne(queryWrapper);
if (user != null) {
UserDetails userDetails = new UserDetails();
BeanUtils.copyProperties(user, userDetails); // 用户角色
Set<GrantedAuthority> authorities = new HashSet<>(); // 查询用户角色
List<Role> roleList = roleService.findByUserId(userDetails.getId());
roleList.forEach(role -> {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleCode()));
}); userDetails.setAuthorities(authorities); return userDetails;
}
return null;
} }
  • 增加用户登录验证处理类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component; import com.c3stones.security.entity.UserDetails;
import com.c3stones.security.service.UserDetailsService; import cn.hutool.core.util.StrUtil; /**
* 用户登录验证处理类
*
* @author CL
*
*/
@Component
public class UserAuthenticationProvider implements AuthenticationProvider { @Autowired
private UserDetailsService userDetailsService; /**
* 身份验证
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取用户名
String username = (String) authentication.getPrincipal();
// 获取密码
String password = (String) authentication.getCredentials(); UserDetails userDetails = (UserDetails) userDetailsService.loadUserByUsername(username);
if (userDetails == null) {
throw new UsernameNotFoundException("用户名不存在");
} if (!StrUtil.equals(username, userDetails.getUsername())
|| !new BCryptPasswordEncoder().matches(password, userDetails.getPassword())) {
throw new BadCredentialsException("用户名或密码错误");
} return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
} /**
* 支持指定的身份验证
*/
@Override
public boolean supports(Class<?> authentication) {
return true;
} }
  • 增加用户权限注解处理类
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component; import com.c3stones.security.entity.UserDetails;
import com.c3stones.sys.entity.Auth;
import com.c3stones.sys.service.AuthService; /**
* 用户权限注解处理类
*
* @author CL
*
*/
@Component
public class UserPermissionEvaluator implements PermissionEvaluator { @Autowired
private AuthService authService; /**
* 判断是否拥有权限
*
* @param authentication 用户身份
* @param targetUrl 目标路径
* @param permission 路径权限
*
* @return 是否拥有权限
*/
@Override
public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal(); // 用户权限
Set<String> permissions = new HashSet<String>(); // 查询用户权限
List<Auth> authList = authService.findByUserId(userDetails.getId());
authList.forEach(auth -> {
permissions.add(auth.getPermission());
}); // 判断是否拥有权限
if (permissions.stream().filter(p -> (permission.toString().startsWith(p))).count() > 0) {
return true;
}
return false;
} @Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission) {
return false;
} }
  • 增加无权限处理类
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component; /**
* 无权限处理类
*
* @author CL
*
*/
@Component
public class UserAccessDeniedHandler implements AccessDeniedHandler { @Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
response.sendError(403);
} }
  • 增加登录失败处理类
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component; import com.c3stones.common.vo.Response; /**
* 登录失败处理类
*
* @author CL
*
*/
@Component
public class UserLoginFailureHandler implements AuthenticationFailureHandler { @Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException {
Response.responseJson(response, Response.error(500, "登录失败", exception.getMessage()));
}
}
  • 增加登录成功处理类
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component; import com.c3stones.common.vo.Response; /**
* 登录成功处理类
*
* @author CL
*
*/
@Component
public class UserLoginSuccessHandler implements AuthenticationSuccessHandler { @Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException {
Response.responseJson(response, Response.success("登录成功"));
}
}
  • 增加登出成功处理类
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component; /**
* 登出成功处理类
*
* @author CL
*
*/
@Component
public class UserLogoutSuccessHandler implements LogoutSuccessHandler { @Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
SecurityContextHolder.clearContext();
response.sendRedirect("login");
}
}
  • 增加未登录处理类
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component; /**
* 未登录处理类
*
* @author CL
*
*/
@Component
public class UserNotLoginHandler implements AuthenticationEntryPoint { @Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(403);
}
}
  • 增加系统安全核心配置,取代之前的系统配置类、登录拦截器和登录相关认证逻辑

      本系统不是前后端分离系统,因此还是通过Session进行管理。
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; import com.c3stones.security.UserAuthenticationProvider;
import com.c3stones.security.UserPermissionEvaluator;
import com.c3stones.security.handle.UserAccessDeniedHandler;
import com.c3stones.security.handle.UserLoginFailureHandler;
import com.c3stones.security.handle.UserLoginSuccessHandler;
import com.c3stones.security.handle.UserLogoutSuccessHandler;
import com.c3stones.security.handle.UserNotLoginHandler; import lombok.Setter; /**
* 系统安全核心配置
*
* @author CL
*
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ConfigurationProperties(prefix = "security.web")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /**
* 忽略的URL
*/
@Setter
private List<String> excludes; /**
* 无权限处理类
*/
@Autowired
private UserAccessDeniedHandler userAccessDeniedHandler; /**
* 用户未登录处理类
*/
@Autowired
private UserNotLoginHandler userNotLoginHandler; /**
* 用户登录成功处理类
*/
@Autowired
private UserLoginSuccessHandler userLoginSuccessHandler; /**
* 用户登录失败处理类
*/
@Autowired
private UserLoginFailureHandler userLoginFailureHandler; /**
* 用户登出成功处理类
*/
@Autowired
private UserLogoutSuccessHandler userLogoutSuccessHandler; /**
* 用户登录验证
*/
@Autowired
private UserAuthenticationProvider userAuthenticationProvider; /**
* 用户权限注解
*/
@Autowired
private UserPermissionEvaluator userPermissionEvaluator; /**
* 加密方式
*
* @return
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
} /**
* 注入自定义PermissionEvaluator
*
* @return
*/
@Bean
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(userPermissionEvaluator);
return handler;
} /**
* 用户登录验证
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(userAuthenticationProvider);
} /**
* 安全权限配置
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().sameOrigin() // 可以相同域名页面的frame中展示
.and().authorizeRequests() // 权限配置
.antMatchers(excludes.toArray(new String[excludes.size()])).permitAll()// 获取白名单(不进行权限验证)
.anyRequest().authenticated() // 其他的需要登陆后才能访问
.and().httpBasic().authenticationEntryPoint(userNotLoginHandler) // 配置未登录处理类
.and().formLogin().loginPage("/login").loginProcessingUrl("/login") // 配置登录URL
.successHandler(userLoginSuccessHandler) // 配置登录成功处理类
.failureHandler(userLoginFailureHandler) // 配置登录失败处理类
.and().logout().logoutUrl("/logout")// 配置登出地址
.logoutSuccessHandler(userLogoutSuccessHandler) // 配置用户登出处理类
.and().exceptionHandling().accessDeniedHandler(userAccessDeniedHandler)// 配置没有权限处理类
.and().csrf().disable(); // 禁用跨站请求伪造防护
} }
  • 其他角色、权限添加、删除、绑定等功能,请下载项目源码,启动项目查看
  • 给系统Controller添加权限注解(以UserController为例)
import javax.validation.constraints.NotNull;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.c3stones.common.vo.Response;
import com.c3stones.sys.entity.User;
import com.c3stones.sys.service.UserService; import cn.hutool.crypto.digest.BCrypt; /**
* 系统用户Controller
*
* @author CL
*
*/
@Controller
@RequestMapping(value = "user")
public class UserController { @Autowired
private UserService userService; /**
* 查询列表
*
* @return
*/
@PreAuthorize(value = "hasPermission('/user/list', 'sys:user:view')")
@RequestMapping(value = "list")
public String list() {
return "pages/sys/userList";
} /**
* 查询列表数据
*
* @param user 系统用户
* @param current 当前页
* @param size 每页显示条数
* @return
*/
@PreAuthorize(value = "hasPermission('/user/listData', 'sys:user:view')")
@RequestMapping(value = "listData")
@ResponseBody
public Response<Page<User>> listData(User user, @RequestParam(name = "page") long current,
@RequestParam(name = "limit") long size) {
Page<User> page = userService.listData(user, current, size);
return Response.success(page);
} /**
* 新增
*
* @return
*/
@PreAuthorize(value = "hasPermission('/user/add', 'sys:user:edit')")
@RequestMapping(value = "add")
public String add() {
return "pages/sys/userAdd";
} /**
* 检验用户名称是否唯一
*
* @param userName 用户名称
* @return
*/
@PreAuthorize(value = "hasPermission('/user/check', 'sys:user:edit')")
@RequestMapping(value = "check")
@ResponseBody
public Response<Boolean> checkUserName(@NotNull String username) {
Boolean checkResult = userService.checkUserName(username);
return Response.success(checkResult);
} /**
* 保存
*
* @param user 系统用户
* @return
*/
@PreAuthorize(value = "hasPermission('/user/save', 'sys:user:edit')")
@RequestMapping(value = "save")
@ResponseBody
public Response<Boolean> save(User user) {
user.setPassword(BCrypt.hashpw(user.getPassword()));
boolean result = userService.save(user);
return Response.success(result);
} /**
* 修改
*
* @param user 系统用户
* @param model
* @return
*/
@PreAuthorize(value = "hasPermission('/user/edit', 'sys:user:edit')")
@RequestMapping(value = "edit")
public String edit(User user, Model model) {
Assert.notNull(user.getId(), "ID不能为空");
model.addAttribute("user", userService.getById(user.getId()));
return "pages/sys/userEdit";
} /**
* 更新
*
* @param user 系统用户
* @return
*/
@PreAuthorize(value = "hasPermission('/user/update', 'sys:user:edit')")
@RequestMapping(value = "update")
@ResponseBody
public Response<Boolean> update(User user) {
Assert.notNull(user.getId(), "ID不能为空");
boolean result = userService.updateById(user);
return Response.success(result);
} /**
* 删除
*
* @param user 系统用户
* @return
*/
@PreAuthorize(value = "hasPermission('/user/delete', 'sys:user:edit')")
@RequestMapping(value = "delete")
@ResponseBody
public Response<Boolean> delete(User user) {
Assert.notNull(user.getId(), "ID不能为空");
boolean result = userService.removeById(user.getId());
return Response.success(result);
} }

6. 测试

  • 登录(system/123456或user/123456)

      用户名或密码错误



      用户名和密码正确

  • 系统管理员登录(system/123456)
  • 用户管理

  • 用户角色

  • 角色绑定用户



  • 角色权限

  • 权限绑定角色



  • 任务调度

  • 普通用户登录(user/123456)
  • 删除用户



  • 给角色添加用户

  • 任务调度

7. 项目地址

  spring-security-quartz-demo

SpringBoot + SpringSecurity + Quartz + Layui实现系统权限控制和定时任务的更多相关文章

  1. 基于Vue实现后台系统权限控制

    原文地址:http://refined-x.com/2017/08/29/基于Vue实现后台系统权限控制/,转载请注明出处. 用Vue/React这类双向绑定框架做后台系统再适合不过,后台系统相比普通 ...

  2. SpringSecurity 自定义用户 角色 资源权限控制

    SpringSecurity 自定义用户 角色 资源权限控制 package com.joyen.learning.security; import java.sql.ResultSet; impor ...

  3. angular基于ui-router实现系统权限控制

    前端去实现权限控制听起来有点扯淡(实际也有点扯淡),掩耳盗铃,主要是担心安全问题,但是如果在前后端分离的情况下,需要做一个带有权限控制的后台管理系统,angular基于ui-router应该怎么做呢? ...

  4. 基于SpringBoot+SpringSecurity+mybatis+layui实现的一款权限系统

    这是一款适合初学者学习权限以及springBoot开发,mybatis综合操作的后台权限管理系统 其中设计到的数据查询有一对一,一对多,多对多,联合分步查询,充分利用mybatis的强大实现各种操作, ...

  5. springboot shiro和freemarker集成之权限控制完全参考手册(跳过认证,登录由三方验证,全网首发)

    本文主要考虑单点登录场景,登录由其他系统负责,业务子系统只使用shiro进行菜单和功能权限校验,登录信息通过token从redis取得,这样登录验证和授权就相互解耦了. 用户.角色.权限进行集中式管理 ...

  6. springboot+mybatis+shiro——登录认证和权限控制

    转载:https://z77z.oschina.io/ 一.引入依赖 shiro-all包含shiro所有的包.shiro-core是核心包.shiro-web是与web整合.shiro-spring ...

  7. Vue-Access-Control:前端用户权限控制解决方案

    原文地址:http://refined-x.com/2017/11/28/Vue2.0用户权限控制解决方案/ Vue-Access-Control是一套基于Vue/Vue-Router/axios 实 ...

  8. SpringBoot系列——Security + Layui实现一套权限管理后台模板

    前言 Spring Security官网:https://spring.io/projects/spring-security Spring Security是一个功能强大且高度可定制的身份验证和访问 ...

  9. spring-security权限控制详解

    在本例中,主要讲解spring-boot与spring-security的集成,实现方式为: 将用户.权限.资源(url)采用数据库存储 自定义过滤器,代替原有的 FilterSecurityInte ...

随机推荐

  1. JS简单介绍与简单的基本语法

    1.JavaScirpt是一门编程语言,是为前端服务的一门语言. (1)基础语法 (2)数据类型 (3)函数 (4)面向对象 2.还涉及到BOM和DOM (1)BOM(操作浏览器的一些功能) (2)D ...

  2. 好学易懂 从零开始的插头DP(一)

    好学易懂 从零开始的插头DP(一) 写在前面 这是一篇,以蒟蒻视角展开的梳理总结.更改了一些顺序,变化了一些细节.方便蒟蒻学习理解(起码本蒟蒻是这样).大佬们可以直接看其它大佬的博客,可以学的更快. ...

  3. phpstudy搭建网站只能访问首页,其他路由访问404

    今天博主遇到了一个很奇葩的问题,电脑下载了一个phpstudy搭建网站,框架用的是tp,但是除了输入域名能访问,其他页面都访问不了 经过博主的疯狂问大佬,以及百度,终于解决了这个问题 这次出现问题的原 ...

  4. level2行情是什么意思?

    level2行情是由上海证券交易所推出的实时行情信息收费服务产品,主要提供在上海证券交易所上市交易的证券产品的实时交易数据,包括十档行情,买卖队列,逐笔成交,委托总量和加权价格等数据. 投资者根据其功 ...

  5. 苹果电脑不安装flash的话怎么看直播

    直播这种娱乐方式的兴起,让很多游戏玩家.脱口秀演员.歌手等拥有了一个更加宽广的舞台,可以更好地展现自己的才能.大部分的直播都是采取视频影像的方式直播,只有少部分才会采用纯音频的方式. 由于很多直播网站 ...

  6. 关于UILabel标签控件的使用小节

    前段时间一直想停下来,总结一下近期在开发中遇到的一些问题顺便分享一下解决问题的思路和方法,无奈人生就像蒲公英,看似自由却身不由己.太多的时间和精力被占用在新项目的开发和之前项目的维护中,总之一句话外包 ...

  7. JQuery案例:购物车编辑

    购物车编辑 实现了:商品的加减,总价的变动 实现了:全选/全不选(使用prop而不是attr) 实现了:删除(遮罩层) <html> <head> <meta chars ...

  8. 第一次个人作业 - 软件工程与UML

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE1/ 这个作业要求在哪里 https://edu.cnblogs.com/campus/f ...

  9. 【2020.11.30提高组模拟】剪辣椒(chilli)

    剪辣椒(chilli) 题目描述 在花园里劳累了一上午之后,你决定用自己种的干辣椒奖励自己. 你有n个辣椒,这些辣椒用n-1条绳子连接在一起,任意两个辣椒通过用若干个绳子相连,即形成一棵树. 你决定分 ...

  10. charles 常用功能(七)简易接口压力测试(repeat advance 功能)

    接口请求次数.并发量.请求延迟时间均可配置 1.选中需要进行测试的接口,鼠标右键 选中[repeat advance] 设置迭代数量