目录
前言
1.什么是RBAC模型权限控制
2.RBAC权限模型的数据库表如何设置
3.整合ssm+Spring security4
3.1引入依赖
3.2web文件
3.3applicationContent.xml文件
3.4spring-security.xml文件
4.异步处理登录成功和登录失败
5.密码加密
6.自定义图形验证码
通过jsp页面制作验证码imagecode.jsp
加载验证码控制器
在spring security配置文件中放心imagecode请求
在登陆页面加载验证码
自定义过滤器比对验证码
Spring security配置文件中引入过滤器
7.remember –me
登陆页面添加remember-me
在security中配置remember的bean以及
使用remember-me
8.security标签库的使用
加入标签库的依赖
在jsp页面导入标签库
使用标签
9.获取登陆后的用户信息
用心写好每一篇文章,真心对待每一个读者
文章首发地址: www.javayihao.top
首发公众号: java一号
RBAC主要是用户、角色、以及权限三者关系,用户与角色相关联,角色与权限相关联,用户通过成为适当角色的成员而得到这些角色的权限。简化了系统中权限的控制
总共需要用户表 、角色表、 权限表三张基础表,另外还有用户和角色是多对多有一张中间表,角色和权限是多对多有一张中间表,如下数据库sss的sql语句
-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`permName` varchar(255) DEFAULT NULL,
`permTag` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES ('1', '增加商品', 'ROLE_ADD');
INSERT INTO `sys_permission` VALUES ('2', '删除商品', 'ROLE_DELETE');
INSERT INTO `sys_permission` VALUES ('3', '修改商品', 'ROLE_UPDATE');
INSERT INTO `sys_permission` VALUES ('4', '查询商品', 'ROLE_LIST');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`roleName` varchar(255) DEFAULT NULL,
`roleDesc` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '普通用户', '普通用户');
INSERT INTO `sys_role` VALUES ('2', '管理员 ', '管理员');
-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`role_id` int(11) NOT NULL,
`perm_id` int(11) NOT NULL,
PRIMARY KEY (`role_id`,`perm_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- 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 ('2', '3');
INSERT INTO `sys_role_permission` VALUES ('2', '4');
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`realname` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`createDate` date DEFAULT NULL,
`lastLoginTime` date DEFAULT NULL,
`enabled` int(11) DEFAULT NULL,
`accountNonExpired` int(11) DEFAULT NULL,
`accountNonLocked` int(11) DEFAULT NULL,
`credentialsNonExpired` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', '123', '张三', '123', '2019-05-13', '2019-05-13', '1', '1', '1', '1');
INSERT INTO `sys_user` VALUES ('2', '456', '李四', '123', '2019-05-13', '2019-05-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(11) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `sys_user_role` VALUES ('2', '2');
org.springframework
spring-core
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework.security
spring-security-web
${spring.security.version}
org.springframework.security
spring-security-config
${spring.security.version}
jstl
jstl
${jstl.version}
javax.servlet
servlet-api
${servlet.version}
provided
com.fasterxml.jackson.core
jackson-databind
2.9.5
org.mybatis
mybatis
3.4.4
org.mybatis
mybatis-spring
1.3.0
com.alibaba
druid
1.1.7
mysql
mysql-connector-java
5.1.41
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:applicationContent.xml
classpath:spring-security.xml
DispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:Springmvc.xml
1
DispatcherServlet
/
完整代码,请关注微信公众号 java一号 回复ssms原文获取
访问项目
使用用户123访问能够正常访问添加和删除页面,但是当访问查询和修改页面,会显示权限不足的提示,说明我们整合spring security4成功。
上面的登录是同步的过程,下面通过异步处理登录业务,首先和spring security入门篇一样,自定义myAuthenticationFailureHandler和MyAuthenticationSuccessHandler两个业务类,代码如下
package com.javayihao.top.sss.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @Author lupenghu
* @Des
* @Date create in 11:112019/5/28
* @
*/
public class myAuthenticationFailureHandler implements AuthenticationFailureHandler {
//使用spring默认支持的json数据处理依赖包,将对象转成json格式的字符串
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
Map map = new HashMap<>();
map.put("success", false);
String jsonStr = objectMapper.writeValueAsString(map);
response.setContentType("text/json;Charset=utf-8");
response.getWriter().write(jsonStr);
}
}
package com.javayihao.top.sss.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @Author lupenghu
* @Des
* @Date create in 10:572019/5/28
* @
*/
/*
如果使用异步登陆,
自定义成功类需要实现AuthenticationSuccessHandler成功接口
*/
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
//使用spring默认支持的json数据处理依赖包,将对象转成json格式的字符串
private ObjectMapper objectMapper = new ObjectMapper();
/*
authentication代表认证成功后的信息
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map map = new HashMap<>();
map.put("success", true);
String jsonStr = objectMapper.writeValueAsString(map);
response.setContentType("text/json;Charset=utf-8");
response.getWriter().write(jsonStr);
}
}
在Spring security配置文件中引用
登陆页面使用ajax异步登陆
<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
登陆
登陆界面
用户名或密码错误
<%--如果使用异步登陆--%>
Spring security提供了一个接口PasswordEncoder用来对用户密码加密,可以查看一下这个接口源代码
public interface PasswordEncoder {
//对输入的密码进行加密,通过hash算法加盐值实现的
String encode(CharSequence var1);
//匹配密码
boolean matches(CharSequence var1, String var2);
}
测试代码
public static void main(String[] args) {
//使用PasswordEncoder接口的实现类BCryptPasswordEncoder()加密字符串
PasswordEncoder encoder = new BCryptPasswordEncoder();
System.out.println(encoder.encode("123456"));
//结果是: $2a$10$dlZ4vbMw/qPqoLIgCF8A/OUMi.1qKRL6.wh88Aj.l1dzzW7faIXC6
}
我们把数据库中用户名是123的用户密码改成上面加密后的结果
然后在只需在spring security配置文件中配置如图所示的代码,即可达到密码加密与比对
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="java.awt.image.BufferedImage"%>
<%@page import="javax.imageio.ImageIO"%>
<%@ page import="java.awt.*" %>
<%@ page import="java.io.OutputStream" %>
<%
int width=80;
int height=32;
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
Graphics g = image.getGraphics();
g.setColor(new Color(0xDCDCDCD));
g.fillRect(0,0,width,height);
g.drawRect(0,0,width-1,height-1);
Random random = new Random();
String hash1 = Integer.toHexString(random.nextInt());
for(int i=0;i<50;i++){
int x = random.nextInt(width);
int y = random.nextInt(height);
g.drawOval(x,y,0,0);
}
String capstr = hash1.substring(0,4);
session.setAttribute("key",capstr);
g.setColor(new Color(0,100,0));
g.setFont(new Font("Candara", Font.BOLD,24));
g.drawString(capstr,8,24);
g.dispose();
response.setContentType("image/jpeg");
out.clear();
out=pageContext.pushBody();
OutputStream stream = response.getOutputStream();
ImageIO.write(image,"jpeg",stream);
stream.close();
%>
@RequestMapping("/imageCode")
public String imagecode(){
return "imagecode";
}
验证码
package com.javayihao.top.sss.security;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Author lupenghu
* @Des
* @Date create in 21:232019/5/28
* @
*/
public class ImageCodeAuthenticationFilter extends OncePerRequestFilter {
private AuthenticationFailureHandler authenticationFailureHandler;
public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
this.authenticationFailureHandler = authenticationFailureHandler;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//判断当前请求是否是登陆请求
if(request.getRequestURI().contains("/login")){
//检验验证码
try{
//用户输入的验证码
final String imageCode =request.getParameter("image");
System.out.println(imageCode+"======================");
//获取系统生成的验证码
String key = (String) request.getSession().getAttribute("key");
if(imageCode==null){
throw new ImageCodeException("验证码必须输入");
}
if(!imageCode.trim().equals(key.trim())){
throw new ImageCodeException("验证码必须一致");
}
}catch (AuthenticationException e){
//交给自定义authenticationFailureHandler处理
authenticationFailureHandler.onAuthenticationFailure(request,response,e);
return;
}
}
filterChain.doFilter(request,response);
}
}
security中提供了remember-me的验证功能
注意name必须是security中的remember-me
记住我
org.springframework.security
spring-security-taglibs
${spring.security.version}
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
security中有以下四个标签
标签1 :
标签2:
标签3:
标签4:
主要常用的是标签3(有指定权限的才可以看见标签内容),比如只有有ROLE_ADD权限的才才可以看到添加
添加
//获取登陆后的用户信息 ,实际获取的就是UserDetail对象
Object prin = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (prin != null) {
if (prin instanceof UserDetails) {
UserDetails userDetails = (UserDetails) prin;
String username = userDetails.getUsername();
model.addAttribute("username", username);
}
}
关注微信公众号 java一号 获取更多java编程资料 实战项目 实战视频教程!