基于Spring AOP实现的权限控制
1.AOP简介
AOP,面向切面编程,往往被定义为促使软件系统实现关注点的分离的技术。系统是由许多不同的组件所组成的,每一个组件负责一块特定的功能。除了实现自身核心功能之外,这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的核心服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点,因为它们会跨越系统的多个组件
下面介绍一下AOP相关的术语:
通知: 通知定义了切面是什么以及何时使用的概念。Spring 切面可以应用5种类型的通知:
前置通知(Before):在目标方法被调用之前调用通知功能。
后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
返回通知(After-returning):在目标方法成功执行之后调用通知。
异常通知(After-throwing):在目标方法抛出异常后调用通知。
环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
连接点:是在应用执行过程中能够插入切面的一个点。
切点: 切点定义了切面在何处要织入的一个或者多个连接点。
切面:是通知和切点的结合。通知和切点共同定义了切面的全部内容。
引入:引入允许我们向现有类添加新方法或属性。
织入:是把切面应用到目标对象,并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期中有多个点可以进行织入:
编译期: 在目标类编译时,切面被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载期:切面在目标加载到JVM时被织入。这种方式需要特殊的类加载器(class loader)它可以在目标类被引入应用之前增强该目标类的字节码。
运行期: 切面在应用运行到某个时刻时被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的。
2.编写Spring AOP的aspect类
package com.sxk.aop;
import com.sxk.entity.Token;
import com.sxk.service.AuthorityService;
import com.sxk.service.TokenService;
import org.apache.commons.fileupload.RequestContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
/**
* Created by stonegeek on 2017/3/4.
*/
@Aspect
public class AroundTest {
@Autowired
TokenService tokenService;
@Autowired
AuthorityService authorityService;
@Pointcut("execution(public * com.sxk.controller.testcontroller.*(..))")
public void testaround(){}
@Around("testaround()")
public Object test(ProceedingJoinPoint jp) throws Throwable{
System.out.println("开始验证Token权限。。。。");
HttpServletRequest request= ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
String tokenName=this.getToken(request);
String url=this.getURL(request);
String method=this.getMethod(request);
System.out.println("Token为:"+tokenName);
System.out.println("URL为:"+url);
System.out.println("Method为:"+method);
Token token=tokenService.findByTokenName(tokenName);
if(token==null)
return "{'result':'Token not exsits'}";
Timestamp creatTime=token.getCreateTime();
int len=token.getEffectiveTime();
Timestamp timeNow=new Timestamp(new Date().getTime());
List<String> allApi=null;
if((creatTime.getTime()+len*1000*60)>=timeNow.getTime()){
allApi=authorityService.getAPI(tokenName);
System.out.println(allApi);
if(allApi!=null&&allApi.contains(url)){
System.out.println("Token验证通过!!!");
return jp.proceed();
}else {
System.out.println("验证失败!!!");
return "{'result':'No authority for this API!!'}";
}
}else {
System.out.println("The Token is Timeout");
return "{'result':'The Token is Timeout!!'}";
}
}
public String getToken(HttpServletRequest request){
return request.getHeader("token");
}
public String getURL(HttpServletRequest request){
return request.getRequestURI();
}
public String getMethod(HttpServletRequest request){
return request.getMethod();
}
}
代码详解:
在管理系统调用后台接口之前,会进行拦截,拦截方法是通过((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()拿到request,在这个request的headers中会有一个key-value(前后台约定的),key为token,value为tokenName,此tokenName为UUID,然后通过这个tokenName从数据库中查询是否有此token,没有的话将返回token not exists字样,有的话 则进行判断此token是否过期,token表中存有token创建时间,还有有效时间,token过期的话,返回the token is timeout!,token有效的话再通过tokenName查询权限表此token的所有允许的API,再对此request和API进行比对,如果包含则允许请求资源,否则返回no authority for this api。
3.登录业务实现类
package com.sxk.service.impl;
import com.sxk.dao.TokenMapper;
import com.sxk.dao.UserMapper;
import com.sxk.service.Login_Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.Date;
import java.util.UUID;
import com.sxk.entity.User;
import com.sxk.entity.Token;
/**
* Created by stonegeek on 2017/3/5.
*/
@Service("login_ServiceImpl")
public class Login_ServiceImpl implements Login_Service {
int effectTime=200;
@Autowired
private UserMapper userMapper;
@Autowired
private TokenMapper tokenMapper;
@Override
public String login(String userName, String password) {
String json=null;
System.out.println("【认证中心】得到用户名和密码分别为:"+userName+","+password);
User user=userMapper.login(userName,password);
System.out.println(user);
Token token;
if (user!=null) {
System.out.println("【认证中心】用户名、密码验证通过!");
UUID tokenName = UUID.randomUUID();
token = new Token();
token.setLoginName(userName);
token.setTokenName(tokenName.toString());
Timestamp timeNow = new Timestamp(new Date().getTime());
token.setCreateTime(timeNow);
token.setEffectiveTime(effectTime);
System.out.println("别再出错了");
if (tokenMapper.findByLoginName(userName) == null) {
tokenMapper.insert(token);
} else {
tokenMapper.updateByPrimaryKeySelective(token);
}
json = "{\"token\":\"" + tokenName.toString() + "\"}";
}else{
json="{\"token\":\"false\"}";
}
System.out.println(json);
return json;
}
}
代码详解:
首先,登录时给了username和password,然后根据这两个字段查询数据库是否有此用户,或者用户的密码是否正确,通过之后,会根据将此username作为loginname存到token表中,于此同时还有一个UUID生成作为tokenname,creatime、effectTime一同存到token表中,当然此操作是有条件的,先根据tokenname判断token表中是否有此token,没有的话在进行insert,有的话则修改token的有效时间和创建时间。
4.AOP配置文件
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="aroundTest" class="com.sxk.aop.AroundTest" />
5.token实体类
package com.sxk.entity;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Created by lenovo on 2017/3/2.
*/
public class Token implements Serializable {
private Integer tokenId;
private String tokenName;
private Timestamp createTime;
private Integer effectiveTime;
private String loginName;
public Integer getTokenId() {
return tokenId;
}
public void setTokenId(Integer tokenId) {
this.tokenId = tokenId;
}
public String getTokenName() {
return tokenName;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
public Integer getEffectiveTime() {
return effectiveTime;
}
public void setEffectiveTime(Integer effectiveTime) {
this.effectiveTime = effectiveTime;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
}
6.数据库模型
7.关于UUID.randomUUID()简单介绍
UUID.randomUUID().toString()是javaJDK提供的一个自动生成主键的方法。UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,是由一个十六位的数字组成,表现出来的形式。由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。
8.总结
此权限控制省略了对其他业务类的操作,比如说用户的CRUD模块、权限的CRUD模块、API的CRUD模块、角色的CRUD模块以及各个模块之间的关联管理,不过核心部分已经介绍差不多了。
实际开发当中,要根据具体的需求来修改代码的结构实现等等!
基于Spring AOP实现的权限控制的更多相关文章
- 基于Vue实现后台系统权限控制
原文地址:http://refined-x.com/2017/08/29/基于Vue实现后台系统权限控制/,转载请注明出处. 用Vue/React这类双向绑定框架做后台系统再适合不过,后台系统相比普通 ...
- 基于Spring Aop实现类似shiro的简单权限校验功能
在我们的web开发过程中,经常需要用到功能权限校验,验证用户是否有某个角色或者权限,目前有很多框架,如Shiro Shiro有基于自定义登录界面的版本,也有基于CAS登录的版本,目前我们的系统是基于C ...
- 别再让你的微服务裸奔了,基于 Spring Session & Spring Security 微服务权限控制
微服务架构 网关:路由用户请求到指定服务,转发前端 Cookie 中包含的 Session 信息: 用户服务:用户登录认证(Authentication),用户授权(Authority),用户管理(R ...
- 基于Spring框架应用的权限控制系统的研究和实现
摘 要: Spring框架是一个优秀的多层J2EE系统框架,Spring本身没有提供对系统的安全性支持.Acegi是基于Spring IOC 和 AOP机制实现的一个安全框架.本文探讨了Acegi安全 ...
- 从零开始学 Java - Spring AOP 实现用户权限验证
每个项目都会有权限管理系统 无论你是一个简单的企业站,还是一个复杂到爆的平台级项目,都会涉及到用户登录.权限管理这些必不可少的业务逻辑.有人说,企业站需要什么权限管理阿?那行吧,你那可能叫静态页面,就 ...
- Spring AOP 实现功能权限校验功能
版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 使用拦截器实现未登录时跳转到登录界面的功能 1 拦截器SecurityInterceptor 2spring-mvcxml拦 ...
- AOP 下的权限控制实现
摘要 面向方面的编程(AOP)是一种新的编程技术,它弥补了面向对象的编程(OOP)在跨越模块行为上的不足.AOP 引进了 Aspect,它将影响多个类的行为封装到一个可重用模块中,它允许程序员对横切 ...
- 基于Spring aop写的一个简单的耗时监控
前言:毕业后应该有一两年没有好好的更新博客了,回头看看自己这一年,似乎少了太多的沉淀了.让自己做一个爱分享的人,好的知识点拿出来和大家一起分享,一起学习. 背景: 在做项目的时候,大家肯定都遇到对一些 ...
- 基于资源名的MVC权限控制
在程序复杂程度不断上升的过程中,无可避免需要触碰到权限控制,而权限控制又与业务逻辑紧紧相关,市场上出现了大量的权限控制产品,而程序的开发,讲究去繁化简的抽象,在我的开发过程中,逐渐发现程序的权限控制核 ...
随机推荐
- Jmeter基础教程图文版(二)- 核心组件
⚪Jmeter Apache JMeter 是 Apache 组织开发的基于 Java 的压力测试工具.用于对软件做压力测试,它最初被设计用于 Web 应用测试,但后来扩展到其他测试领域. 它可以用于 ...
- 分布式Id - redis方式
本篇分享内容是关于生成分布式Id的其中之一方案,除了redis方案之外还有如:数据库,雪花算法,mogodb(object_id也是数据库)等方案,对于redis来说是我们常用并接触比较多的,因此主要 ...
- Flink文章测试
Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 ...
- 机器学习Label Encoder和One Hot Encoder
标签编码(Label Encoder) 在本例中第一列是Country, 如果我们要运行任何模型, 数据中不能包含文本 所以要对文本进行处理 接下来,我们从sklearn库中导入LabelEncode ...
- 安全性测试:OWASP ZAP 2.8 使用指南(二):ZAP基础操作
ZAP桌面应用 ZAP桌面应用由以下元素组成: 1. 菜单栏 – 提供多种自动化和手动工具的访问 2. 工具栏 – 提供快速访问最常用组件的用户接口 3. 树结构窗口 – 展示被测网站树结构和脚 ...
- Nightmare Ⅱ(双向BFS)
Problem Description Last night, little erriyue had a horrible nightmare. He dreamed that he and his ...
- Chrome 谷歌浏览器安装使用 Postman 和 Sense 插件
博客地址:http://www.moonxy.com 一.前言 Google Chrome 的特点是简洁.快速等.Chrome 支持多标签浏览,每个标签页面都在独立的"沙箱"内运行 ...
- Linux 笔记 - 第十三章 Linux 系统日常管理之(一)系统状态监控
博客地址:http://www.moonxy.com 一.前言 如果你是一名 Linux 运维人员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.系统运行状态主要包括:系统负载.内存状态 ...
- Qt无边框窗体-模拟模态窗体抖动效果
目录 一.概述 二.效果展示 三.功能实现 四.相关文章 原文链接:Qt无边框窗体-模拟模态窗体抖动效果 一.概述 用Qt开发windows客户端界面确实是一大利器,兼顾性能的同时,速度相对来说也不错 ...
- 使用Hexo搭建个人博客并部署到GitHub或码云上全过程
一.前言 如上图所示:GitHub有Github Pages,而码云也有码云 Pages 1.Github Pages或Gitee Pages是什么呢? Github Pages或者Gitee Pag ...