spring security一个能够为基于Spring的企业应用系统提供声明式的安全訪问控制解决方式的安全框架(简单说是对访问权限进行控制嘛),应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。 spring security的主要核心功能为 认证和授权,所有的架构也是基于这两个核心功能去实现的。
pom.xml
需要导入这个jar包
<!-->spring-boot 整合security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
application.yml
# DataSource Config
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
p6spy: false
username: root
password: 123456
url: jdbc:mysql://localhost:3306/rbca_db?characterEncoding=utf8&useSSL=false
freemarker:
allow-request-override: false
cache: false
check-template-location: true
charset: UTF-8
content-type: text/html; charset=utf-8
expose-request-attributes: false
expose-session-attributes: false
expose-spring-macro-helpers: false
suffix: .ftl
template-loader-path: classpath:/templates
logging:
level:
com.wangtao.dao: error
mybatis-plus:
mapper-locations: classpath:mapper/*.xml,classpath:mapper/*/*.xml
sql文件 5张表
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50712
Source Host : localhost:3306
Source Schema : rbca_db
Target Server Type : MySQL
Target Server Version : 50712
File Encoding : 65001
Date: 07/01/2020 14:39:02
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` int(10) NOT NULL,
`permName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`permTag` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求url',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (1, '查询订单', 'showOrder', '/showOrder');
INSERT INTO `sys_permission` VALUES (2, '添加订单', 'addOrder', '/addOrder');
INSERT INTO `sys_permission` VALUES (3, '修改订单', 'updateOrder', '/updateOrder');
INSERT INTO `sys_permission` VALUES (4, '删除订单', 'deleteOrder', '/deleteOrder');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(10) NOT NULL,
`roleName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`roleDesc` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'admin', '管理员');
INSERT INTO `sys_role` VALUES (2, 'add_user', '添加管理员');
-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`role_id` int(10) NULL DEFAULT NULL,
`perm_id` int(10) NULL DEFAULT NULL,
INDEX `FK_Reference_3`(`role_id`) USING BTREE,
INDEX `FK_Reference_4`(`perm_id`) USING BTREE,
CONSTRAINT `FK_Reference_3` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `FK_Reference_4` FOREIGN KEY (`perm_id`) REFERENCES `sys_permission` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (1, 1);
INSERT INTO `sys_role_permission` VALUES (1, 2);
INSERT INTO `sys_role_permission` VALUES (1, 3);
INSERT INTO `sys_role_permission` VALUES (1, 4);
INSERT INTO `sys_role_permission` VALUES (2, 1);
INSERT INTO `sys_role_permission` VALUES (2, 2);
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(10) NOT NULL,
`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`realname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`createDate` date NULL DEFAULT NULL,
`lastLoginTime` date NULL DEFAULT NULL,
`enabled` int(5) NULL DEFAULT NULL,
`accountNonExpired` int(5) NULL DEFAULT NULL,
`accountNonLocked` int(5) NULL DEFAULT NULL,
`credentialsNonExpired` int(5) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'admin', '张三', '15a013bcac0c50049356b322e955035e', '2018-11-13', '2018-11-13', 1, 1, 1, 1);
INSERT INTO `sys_user` VALUES (2, 'userAdd', '小余', '15a013bcac0c50049356b322e955035e', '2018-11-13', '2018-11-13', 1, 1, 1, 1);
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`user_id` int(10) NULL DEFAULT NULL,
`role_id` int(10) NULL DEFAULT NULL,
INDEX `FK_Reference_1`(`user_id`) USING BTREE,
INDEX `FK_Reference_2`(`role_id`) USING BTREE,
CONSTRAINT `FK_Reference_1` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `FK_Reference_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1);
INSERT INTO `sys_user_role` VALUES (2, 2);
SET FOREIGN_KEY_CHECKS = 1;
下面是代码
实体类User
package com.wangtao.entity.security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Data;
// 用户信息表
@Data
public class User implements UserDetails {
private Integer id;
private String username;
private String realname;
private String password;
private Date createDate;
private Date lastLoginTime;
private boolean enabled;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
// 用户所有权限
private List<GrantedAuthority> authorities=new ArrayList();
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
}
实体类Role
package com.wangtao.entity.security;
import lombok.Data;
// 角色信息表
@Data
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
}
实体类Permission
package com.wangtao.entity.security;
import lombok.Data;
@Data
public class Permission {
private Integer id;
// 权限名称
private String permName;
// 权限标识
private String permTag;
// 请求url
private String url;
}
MyUserDetailService 为用户设置权限的地方
package com.wangtao.entity.security;
import com.wangtao.mapper.UserMappers;
import com.wangtao.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class MyUserDetailService implements UserDetailsService{
@Autowired
private UserMappers userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.findByUsername(username);
List<GrantedAuthority> list = new ArrayList<>();
List<Permission> permissions = userMapper.findPermissionByUsername(username);
if (permissions != null && permissions.size() > 0) {
for (Permission permission : permissions) {
list.add(new SimpleGrantedAuthority(permission.getPermTag()));
}
}
user.setAuthorities(list);
return user;
}
}
mapper文件
UserMapper
package com.wangtao.mapper;
import java.util.List;
import com.wangtao.entity.security.Permission;
import com.wangtao.entity.security.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface UserMappers {
// 查询用户信息
@Select(" select * from sys_user where username = #{userName}")
User findByUsername(@Param("userName") String userName);
// 查询用户的权限
@Select(" select permission.* from sys_user user" + " inner join sys_user_role user_role"
+ " on user.id = user_role.user_id inner join "
+ "sys_role_permission role_permission on user_role.role_id = role_permission.role_id "
+ " inner join sys_permission permission on role_permission.perm_id = permission.id where user.username = #{userName};")
List<Permission> findPermissionByUsername(@Param("userName") String userName);
}
PermissionMapper
package com.wangtao.mapper;
import java.util.List;
import com.wangtao.entity.security.Permission;
import org.apache.ibatis.annotations.Select;
public interface PermissionMapper {
@Select(" select * from sys_permission ")
List<Permission> findAllPermission();
}
Controller文件
OrderController
package com.wangtao.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class OrderController {
// 首页
@RequestMapping("/")
public String index() {
return "index";
}
// 查询订单
@RequestMapping("/showOrder")
public String showOrder() {
return "showOrder";
}
// 添加订单
@RequestMapping("/addOrder")
public String addOrder() {
return "addOrder";
}
// 修改订单
@RequestMapping("/updateOrder")
public String updateOrder() {
return "updateOrder";
}
// 删除订单
@RequestMapping("/deleteOrder")
public String deleteOrder() {
return "deleteOrder";
}
// 自定义登陆页面
@GetMapping("/login")
public String login() {
return "login";
}
}
ErrorController
package com.wangtao.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ErrorController {
@GetMapping("/error/403")
public String error(){
return "/error/403";
}
}
用户验证授权配置类
SecurityConfig
package com.wangtao.config;
import com.wangtao.entity.security.MyUserDetailService;
import com.wangtao.entity.security.Permission;
import com.wangtao.handler.MyAuthenticationFailureHandler;
import com.wangtao.handler.MyAuthenticationSuccessHandler;
import com.wangtao.mapper.PermissionMapper;
import com.wangtao.util.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private MyAuthenticationSuccessHandler successHandler;
@Autowired
private MyAuthenticationFailureHandler failureHandler;
@Autowired
private MyUserDetailService myUserDetailService;
@Autowired
private PermissionMapper permissionMapper;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/* auth.inMemoryAuthentication().withUser("admin" ).password("123456").roles("admin");
auth.inMemoryAuthentication().withUser("userAdd").password("123456").roles("userAdd");*/
auth.userDetailsService(myUserDetailService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return MD5Util.encode((String) charSequence);
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return encode(charSequence).equals(s.trim());
}
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
/* http.authorizeRequests().
antMatchers("/showOrder").hasAnyRole("admin","userAdd").
antMatchers("/addOrder").hasAnyRole("admin","userAdd").
antMatchers("/updateOrder").hasAnyRole("admin").
antMatchers("/deleteOrder").hasAnyRole("admin").
antMatchers("/**").fullyAuthenticated().and().formLogin().loginPage("/login").permitAll()
.successHandler(successHandler).failureHandler(failureHandler)
.and()
.logout()
.permitAll().and().csrf().disable();*/
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http.authorizeRequests();
List<Permission> permissions = permissionMapper.findAllPermission();
for (Permission permission : permissions) {
authorizeRequests.antMatchers(permission.getUrl()).hasAnyAuthority(permission.getPermTag());
}
authorizeRequests.antMatchers("/login").permitAll().antMatchers("/**").fullyAuthenticated().and()
.formLogin().loginPage("/login").permitAll().and().logout().permitAll().and().csrf().disable();
}
/* @Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}*/
}
自定义错误页面
@Configuration
public class WebServerAutoConfiguration {
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400");
ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401");
ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN, "/error/403");
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
ErrorPage errorPage415 = new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "/error/415");
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
factory.addErrorPages(errorPage400, errorPage401, errorPage403, errorPage404, errorPage415, errorPage500);
return factory;
}
}
认证成功和认证失败跳转的逻辑
package com.wangtao.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
System.out.println("认证成功!");
httpServletResponse.sendRedirect("/");
}
}
package com.wangtao.handler;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler{
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
System.out.println("认证失败");
httpServletResponse.sendRedirect("https://www.baidu.com");
}
}
login.ftl
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h1>权限控制登陆系统</h1>
<form action="/login" method="post">
<span>用户名称</span><input type="text" name="username" /> <br>
<span>用户密码</span><input type="password" name="password" /> <br>
<input type="submit" value="登陆">
</form>
<#if RequestParameters['error']??>
用户名称或者密码错误
</#if>
</body>
</html>
index.ftl
<h1>订单系统</h1>
<br>
<a href="showOrder">查询订单</a>
<br>
<a href="addOrder">添加订单</a>
<br>
<a href="deleteOrder">删除订单</a>
<br>
<a href="updateOrder">修改订单</a>
showOrder.ftl
<h1>查询订单</h1>
updateOrder.ftl
<h1>修改订单</h1>
addOrder.ftl
<h1>添加订单</h1>
deleteOrder.ftl
<h1>删除订单</h1>
403.ftl
您的权限不足!
logFail.ftl
登陆失败!
输入登录地址,输入错误的密码,点击登录
输入正确的,点击登录
admin用户拥有所有权限,换个普通用户登录
userAdd用户拥有查看和添加权限,点击删除订单
其他操作大家可以自行探索,完毕