SpringSecurity实现权限管理和页面导航栏动态实现
2.2.3 方式2:SpringSecurity注解方式实现权限校验. 20
1 用户模块
1.1 需求:获取用户名
1.1.1 分析
(1) SecurityContext 上下文对象
(2) 查看实现类SecurityContextImpl
(3) 查看Authentication认证对象
Authencication 封装的就是用户信息。
(4) Authentication 实现类: UsernamePasswordAuthenticationToken
此类封装的就是用户密码的token信息
(5) 这里的principal就是指SysUser对象
(6) Authentication 会封装到SecurityContext中
(7) 然后,把SecurityContext绑定到当前线程上。
(8) 最后SecurityContext会存入HttpSession中
(9) 最终:session---àSecurityContext-----àAuthencication-------àSysUser
1.1.2 服务端获取用户信息
/** * 查询全部 */ @RequestMapping("/findAll") public ModelAndView findAll( @RequestParam(required = true,defaultValue = "1") int pageNum, @RequestParam(required = true,defaultValue = "2") int pageSize){ // 测试代码 //1. 获取绑定到当然线程上的SecurityContext SecurityContext securityContext = SecurityContextHolder.getContext(); //2. 获取认证器对象 Authentication authentication = securityContext.getAuthentication(); //3. 获取认证身份信息. 注意这里的user是 // org.springframework.security.core.userdetails.User User user = (User) authentication.getPrincipal(); //4. 获取用户名 // 调用service查询 ModelAndView mv = new ModelAndView(); |
1.1.3 页面获取用户信息
1.1.3.1
如何获取?
(1) SecurityContext对象会存入到HttpSession对象中,怎么证明这一点呢?
我们只需要在任意一个jsp页面写上${sessionScope}就可以看到session里面的全部内容。
{SPRING_SECURITY_CONTEXT= org.springframework.security.core.context.SecurityContextImpl@443cd45f: |
1.1.3.2
方式1:EL
在jsp页面获取用户名,使用EL表达式:
${sessionScope.
SPRING_SECURITY_CONTEXT.authentication.principal.username}
1.1.3.3
方式2:security标签
使用SpringSecurity标签获取用户名:
(1) 先引入标签库描述文件
(2) 使用标签
<security:authentication property="principal.username" />
应用:
1.2 给用户分配角色
1.2.1 需求分析
-- 1.2 给用户分配角色 -- 需求:给userId=1就是jack分配:普通用户、管理员角色 -- 实现: -- 1.先根据用户id,删除用户角色表中数据 DELETE FROM sys_user_role WHERE userId=1; -- 2.再给用户分配角色 INSERT INTO sys_user_role(userId,roleId)VALUES(1,1); INSERT INTO sys_user_role(userId,roleId)VALUES(1,2); |
1.2.2 效果预览
(1) 访问用户列表
点击添加角色:
A. 提交到后台controller
B. 后台
a) 根据用户id查询SysUser用户
b) 获取用户已经具有的角色
String roleStr = “USER,ADMIN,”;
c) 查询所有角色
d) 保存
(2) 查看用户角色列表,如果用户已经有响应角色,就默认选中
页面判断:roleStr是否有包含(USER/ADMIN), 如果有包含,就选中
(3) 最后点击保存,给用户添加角色
1.2.3 进入用户角色列表页面
1.2.3.1 修改user-list.jsp提交地址
1.2.3.2 controller
l 实现思路
(1) 需要查询用户
(2) 查询用户角色
(3) 查询所有角色
(4) 保存以上信息,页面回显
(5) 注意:打断点调试sysUser中的用户id是否有数据.
/** * 用户角色 * (1) 进入用户角色user-role-add.jsp页面 */ @RequestMapping("/toUserRole") public ModelAndView toUserRole(Long id){ // a.查询用户 SysUser sysUser = userService.findById(id); // b.用户具有的角色 List<Role> roles = sysUser.getRoles(); StringBuffer sb = new StringBuffer(); String roleStr=""; if (roles != null && roles.size()>0){ for(Role r : roles){ sb.append(r.getRoleName()+","); }// 去除最后逗号 roleStr = sb.substring(0,sb.length()-1); } // c.查询所有角色 List<Role> roleList = roleService.findAll(); // 返回结果封装 ModelAndView mv = new ModelAndView(); mv.addObject("user",sysUser); mv.addObject("roleStr",roleStr); mv.addObject("roleList",roleList); mv.setViewName("user-role-add"); return mv; } |
(6) 写完上面代码,调试发现根据用户的id查询的SysUser对象中主键值为空,因为查询结果与延迟加载查询结果都有相同的id值,导致影响结果的封装。
解决如下:
1.2.3.3 user-role-add.jsp页面
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> |
<!-- 正文区域 --> <section class="content"> <input type="hidden" name="userId" value="${user.id}"> <table id="dataList" class="table table-bordered table-striped table-hover dataTable"> <thead> <tr> <th class="" style="padding-right: 0px"> <input id="selall" type="checkbox" class="icheckbox_square-blue"></th> <th class="sorting_asc">ID</th> <th class="sorting">角色名称</th> <th class="sorting">角色描述</th> </tr> </thead> <tbody> <c:forEach items="${roleList}" var="role"> <tr> <td><input name="ids" 判断roleStr中是否有包含role.roleName ${fn:contains(roleStr,role.roleName )? 'checked':''} type="checkbox" value="${role.id}"></td> <td>${role.id}</td> <td>${role.roleName }</td> <td>${role.roleDesc}</td> </tr> </c:forEach> </tbody> </table> <!--订单信息/--> <!--工具栏--> <div class="box-tools text-center"> <button type="submit" class="btn bg-maroon">保存</button> <button type="button" class="btn bg-default" onclick="history.back(-1);">返回</button> </div> <!--工具栏/--> </section> <!-- 正文区域 /--> |
1.2.4 保存
1.2.4.1 controller
/** * 用户角色 * (2) 给用户添加角色 */ @RequestMapping("/addRoleToUser") public String addRoleToUser(Long userId,Long[] ids){ userService.addRoleToUser(userId,ids); return "redirect:/user/findAll"; } |
1.2.4.2 service
n 先解除关系,删除中间表数据
n 再往中间表添加数据,即给用户添加角色关系维护
@Override public void addRoleToUser(Long userId, Long[] roleIds) { //1. 先删除中间表当前用户相关的角色数据 //DELETE FROM sys_user_role WHERE userId=1 userDao.deleteUserRole(userId); //2. 添加用户角色关系 if (roleIds != null &&roleIds.length>0){ for(Long roleId : roleIds){ userDao.addUserRole(userId,roleId); } } } |
1.2.4.3 dao
/** * 根据用户删除用户角色关联表数据 * @param userId 用户主键 */ @Select("delete from sys_user_role where userId=#{userId}") void deleteUserRole(Long userId); /** * 添加用户角色关系 * @param userId 用户主键 * @param roleId 角色主键 */ @Insert("insert into sys_user_role(userId,roleId)values(#{userId},#{roleId})") void addUserRole(@Param("userId") Long userId, @Param("roleId") Long roleId); |
2 SpringSecurity 授权功能
2.1 在JSP页面控制菜单权限
2.1.1 基本语法
(1) 页面引入标签库文件
<%@taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
(2) 使用标签
<security:authorize access="hasAnyRole('ROLE_ADMIN')">
标签访问资源需要ROLE_ADMIN角色权限。
(3) 注意
因为这里使用的是SPEL表达式,所以需要开启表达式语言支持。
2.1.2 应用
2.1.2.1 期望结果
(1) 期望结果:不同的用户登陆只显示用户有权限的功能菜单
(2) 例如:Jack是普通用户登陆,
看到的就只有基础数据模块
(3) 例如:Rose是管理员登陆,
看到的就是系统管理模块.
2.1.2.2 页面实现
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="security" uri="http://www.springframework.org/security/tags" %> <aside class="main-sidebar"> <!-- sidebar: style can be found in sidebar.less --> <section class="sidebar"> <!-- Sidebar user panel --> <div class="user-panel"> <div class="pull-left image"> <img src="${pageContext.request.contextPath}/img/user2-160x160.jpg" class="img-circle" alt="User Image"> </div> <div class="pull-left info"> <p> <security:authentication property="principal.username" /> </p> <a href="#"><i class="fa fa-circle text-success"></i> 在线</a> </div> </div> <!-- sidebar menu: : style can be found in sidebar.less --> <ul class="sidebar-menu"> <li class="header">菜单</li> <li id="admin-index"><a href="${pageContext.request.contextPath}/pages/main.jsp"><i class="fa fa-dashboard"></i> <span>首页</span></a></li> <li class="treeview"> <security:authorize access="hasAnyRole('ROLE_ADMIN')"> <a href="#"> <i class="fa fa-cogs"></i> <span>系统管理</span> <span class="pull-right-container"> <i class="fa fa-angle-left pull-right"></i> </span> </a> </security:authorize> <ul class="treeview-menu"> <security:authorize access="hasAnyRole('ROLE_ADMIN')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/user/findAll"> <i class="fa fa-circle-o"></i> 用户管理 </a></li> </security:authorize> <security:authorize access="hasAnyRole('ROLE_ADMIN')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/role/findAll"> <i class="fa fa-circle-o"></i> 角色管理 </a></li> </security:authorize> <security:authorize access="hasAnyRole('ROLE_ADMIN')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/permission/findAll"> <i class="fa fa-circle-o"></i> 权限管理 </a></li> </security:authorize> <security:authorize access="hasAnyRole('ROLE_ADMIN')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/pages/syslog-list.jsp"> <i class="fa fa-circle-o"></i> 访问日志 </a></li> </security:authorize> </ul></li> <li class="treeview"> <security:authorize access="hasAnyRole('ROLE_USER')"> <a href="#"> <i class="fa fa-cube"></i> <span>基础数据</span> <span class="pull-right-container"> <i class="fa fa-angle-left pull-right"></i> </span> </a> </security:authorize> <ul class="treeview-menu"> <security:authorize access="hasAnyRole('ROLE_USER')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/product/findByPage"> <i class="fa fa-circle-o"></i> 产品管理 </a></li> </security:authorize> <security:authorize access="hasAnyRole('ROLE_USER')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/order/findByPage"> <i class="fa fa-circle-o"></i> 订单管理 </a></li> </security:authorize> </ul> </li> </ul> </section> <!-- /.sidebar --> </aside> |
2.2 服务端控制权限
2.2.1 为什么需要在服务端控制权限呢?
(1) 例如普通用户jack登陆系统, 只能看到基础数据。
(2) 但是,直接在浏览器输入地址,也是可以访问角色管理模块的
2.2.2 方式1:JSR-250注解方式权限校验
(1) 刚才菜单没有显示,如果直接访问地址栏,那么也会进入到具体的方法中.
(2) 现在要解决这个问题:使用一些注解来实现权限校验。
(3) 在讲各种注解之前,一定一定需要先配置AOP注解的支持,
而且一定需要在springmvc.xml配置文件中配置
(4) <!-- 开启AOP的支持 --> (5) <aop:aspectj-autoproxy proxy-target-class="true"/> |
(4) 完整应用
第一步:开启Aop注解支持
第二步:JSR-250注解方式权限拦截,需要添加依赖(已经完成)
第三步:在spring-security.xml配置文件中开启JSR-250的注解支持
<security:global-method-security jsr250-annotations="enabled"/> |
第四步:在Controller的类或者方法上添加注解@RolesAllowed
2.2.3 方式2:SpringSecurity注解方式实现权限校验
(1) 在spring-security.xml配置文件中开启注解支持
<security:global-method-security secured-annotations="enabled"></security:global-method-security> |
(2) 在Controller类或者方法添加注解@Secured
2.2.4 方式3:SpEL表达式方式实现权限校验
(1) 在spring-security.xml配置文件中开启注解支持
<!--方式3:spel表达式提供的权限校验支持--> <security:global-method-security pre-post-annotations="enabled"></security:global-method-security> |
(2) 在Controller类或者方法添加注解@PreAuthorize
3 系统日志功能
3.1 需求
希望系统自动记录访问后台controller的时间、方法、来访者ip等信息。
3.2 建表
CREATE TABLE sys_log( id int PRIMARY KEY, visitTime DATE, username VARCHAR2(50), ip VARCHAR2(30), method VARCHAR2(200) ) |
3.3 domain
public class SysLog { private Long id; private Date visitTime; private String username; private String ip; private String method; |
3.4 dao
public interface ISysLogDao { @Insert("insert into sys_log(id,visitTime,username,ip,method) values(seq_log.nextval(),#{visitTime},#{username},#{ip},#{method})") void save(SysLog log); } |
3.5 service
3.5.1 接口
public interface ISysLogService { void save(SysLog sysLog); } |
3.5.2 实现
@Service @Transactional public class SysLogServiceImpl implements ISysLogService { @Autowired private ISysLogDao sysLogDao; @Override public void save(SysLog sysLog) { sysLogDao.save(sysLog); } } |
3.6 编写切面类
3.6.1 先再web.xml配置监听器
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> |
然后再切面类中就可以注入HttpServletRequest对象,获取来访者ip。 |
3.6.2 切面类
package com.itheima.utils; import com.itheima.domain.SysLog; import com.itheima.service.ISysLogService; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.Date; @Component @Aspect public class LogAop { // 注入request对象(需要配置监听器) @Autowired private HttpServletRequest request; @Autowired private ISysLogService sysLogService; @Around("execution(* com.itheima.controller.*Controller.*(..))") public Object arount(ProceedingJoinPoint pjp) { //1. 获取方法参数 Object[] methodArgs = pjp.getArgs(); //2. 获取正在执行的类和方法 //pjp.getSignature().getName(); 方法名称 String methodName = pjp.getSignature().toShortString(); //3. 获取用户 SecurityContext securityContext = SecurityContextHolder.getContext(); Authentication authentication = securityContext.getAuthentication(); User user = (User) authentication.getPrincipal(); String username = user.getUsername(); //4. 获取ip String remoteAddr = request.getRemoteAddr(); //5. 封装 SysLog log = new SysLog(); log.setIp(remoteAddr); log.setMethod(methodName); log.setUsername(username); log.setVisitTime(new Date()); try { // 放行,去到控制器处理请求的方法 Object returnValue = pjp.proceed(methodArgs); //方法执行后增强: 记录日志 sysLogService.save(log); return returnValue; } catch (Throwable e) { e.printStackTrace(); return null; } } } |
3.6.3 注解扫描切面类
3.6.4 访问controller测试
观察数据库中数据变化,
SpringSecurity实现权限管理和页面导航栏动态实现的更多相关文章
- 小程序配置单个页面导航栏的属性(微信小程序交流群:604788754)
配置单个页面导航栏的属性: 就在所要配置页面相对应的json文件中写入以下想要设置的属性: { "navigationBarBackgroundColor": "#fff ...
- AngularJS 导航栏动态添加.active
在传统jQuery中,实现导航栏动态添加.active类的思路比较简单,就是当点击的时候,清除其他.active,然后给当前类加上.active. 但是在AngularJS中,就不能再采用这种jQue ...
- 小程序--改变子级别页面导航栏信息 / navigationBarTitleText
微信小程序在公共文件app.json中设置了导航栏相关样式如下: 其中 navigationBarTitleText 为设置导航栏名称,若是想子级页面和父页面的header页面不同,则在子级文件中新 ...
- 小程序开发-页面导航栏navigation-bar组件
导航栏navigation-bar 页面导航条配置节点,用于指定导航栏的一些属性.只能是 page-meta 组件内的第一个节点,需要配合它一同使用. 通过这个节点可以获得类似于调用 wx.setNa ...
- 移动端html5页面导航栏悬浮遮挡内容第一行解决办法
参考:https://zhidao.baidu.com/question/1608232105428062147.html 1.设置导航栏div属性position:fixed; .nav-fixed ...
- 导航栏动态添加act属性
最近做了一个网站,需要设置导航栏的act属性,这里需要用到addClass以及removeClass: $('#topName li').removeClass('active'); $(this). ...
- 右侧导航栏(动态添加数据到list)
页面样式 <style> .scroll { position: fixed; right: 5%; top: 5em; background: #ccc; display: none; ...
- Dynamics CRM2015 页面导航栏顶部全局快速查找功能配置
在CRM2015中微软加入了新的快速查找功能,让你的数据查找更加方便,功能栏如下图所示,直接可以框中输入搜索项进行搜索. 但该功能是需要进行些配置,具体的配置在设置-管理-系统设置中,默认的就是红框中 ...
- 微信小程序之页面导航栏
效果图: 页面有点丑,作为初次学习,页面可以要求不那么美观,先学会再说.毕竟后面可以优化的很漂亮. 代码实例如下: <view class="section btn-area" ...
随机推荐
- UltraEdit注册机 及使用方法详解
转载自:http://www.iyaxi.com/ultraedit-key/ UltraEdit是一款强大的文字编辑器,很多编程的.搞设计的等等都能用到它,具体功能请自行百度.今天为大家带来UE软件 ...
- C#多条件查出来的多个DataSet,然后循环将数据整合
private List<string> barList; public List<string> BarList { get ...
- MathType7.X链接:https://pan.baidu.com/s/1rQ5Cwk5_CC9UgvgaYPVCCg 提取码:6ojq 复制这段内容后打开百度网盘手机App,操作更方便哦完美解压,无限使用
最近在写论文的过程中使用到了MathType,但是由于MathType30天使用已经过期,有些特殊符号用不了,于是开始找各种破解版.好吧,花了整整两个小时才算搞定,真是一部血泪史,现在把安装破解教程贴 ...
- FreeRTOS 启动进程调度后,程序卡死的部分原因分析。
现象:1,RTOS 使用时 系统卡启动文件 B .处. 原因分析:该种情况是由于定义开启了中断,但是未开启中断处理服务.程序执行到中断响应式无对应的程序响应 ...
- 15 个 Eclipse 常用开发快捷键使用技巧
15 个 Eclipse 常用开发快捷键使用技巧 1.alt+? 或 alt+/:自动补全代码或者提示代码 2.ctrl+o:快速outline视图 3.ctrl+shift+r:打开资源列表 4.c ...
- MyBatis异常:元素内容必须由格式正确的字符数据或标记组成
今天在写接口查询SQL时,报了一个异常,如下: Cause: org.apache.ibatis.builder.BuilderException: Error creating document i ...
- [linux]使用curl进行GET、POST和网页调试
以前在win下开发的时候,习惯用的调试工具是谷歌自带控制台和postman,谷歌控制台比较方便,但不能对请求进行重发,post虽然很好用,但是感觉还是有点'大'.在linux下,其实完全没有那么麻烦, ...
- 基本urllib库
urlib库 urllib库是Python中一个最基本的网络请求库.可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据. urlopen函数: 在Python3的urllib ...
- OpenSSL MD5 API
#include <stdlib.h> #define _GNU_SOURCE /* for getline API */ #include <stdio.h> /* Open ...
- Linux磁盘和文件系统管理
1.检测并确认新硬盘 挂载好新的硬盘设备并启动主机后,Linux系统会自动检测并加载该硬盘,无须额外安装驱动.执行“fdisk -l”命令即可查看,确认新增硬盘的设备名称和位置.作用:列出当前系统中所 ...