前后端分离开发是目前软件开发的主流,大大提高了开发效率
但也带来了很多不方便之处。
1、优点:
① 传统全栈开发的 MVC 模式将不适合,后台采取 MVP 面向接口编程,耦合度大大降低
2、缺点:
① 跨域问题不胜其扰
3、原则:
① 一个合格的后台应全力负责业务逻辑
② 前端不要参与过多的业务逻辑,专注于网页的视觉建设
否则项目耦合度高、网站的安全性低
学过计算机网络
的,都知道,每个人的电脑的 ip 地址是全球唯一的,
我们可以利用 ip 地址在数据库中的记录中的 查询、增加、删除,来进行 拦截、登录、注销
使用 AOP 编程,对指定的方法进行登录拦截
下面以个人最近开发的一个校园外卖网站的后台代码为例(待续),抽取分享相关的代码
package com.cun.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import io.swagger.annotations.ApiModelProperty;
@Entity
@Table(name = "t_login")
public class Login {
@Id
@GeneratedValue
@ApiModelProperty(value = "主键id")
private Integer id;
@Column(length = 100)
private String addressIp; //登录后的主机 ip
private Date date; //登陆时间
private Integer userId; //关联登录的用户id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAddressIp() {
return addressIp;
}
public void setAddressIp(String addressIp) {
this.addressIp = addressIp;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
package com.cun.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import com.cun.entity.Login;
public interface LoginDao extends JpaRepository{
// 注意:delete 操作,dao 接口层加 @Modifying ,在调用层使用 @Transactional
@Modifying
@Query(value = "delete from t_login where address_ip=?1", nativeQuery = true)
void deleteLogin(String addressIp);
@Query(value = "select * from t_login where address_ip=?1 order by date desc limit 1", nativeQuery = true)
Login getLoginByIp(String addressIp);
}
构思最为长久的地方
package com.cun.security;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.cun.dao.LoginDao;
import com.cun.entity.Login;
import com.cun.util.Json;
@Component
@Aspect
public class MySecurity {
@Autowired
private LoginDao loginDao;
private final Logger logger = LoggerFactory.getLogger(MySecurity.class);
@Pointcut("execution(public * com.cun.controller.admin.*.*(..))")
public void log() {
}
@Before("log()")
public void deoBefore(JoinPoint joinPoint) {
logger.info("方法执行前...");
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = sra.getRequest();
logger.info("url:" + request.getRequestURI());
logger.info("ip:" + request.getRemoteHost());
logger.info("method:" + request.getMethod());
logger.info("class_method:" + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName());
logger.info("args:" + joinPoint.getArgs());
}
@After("log()")
public void doAfter(JoinPoint joinPoint) {
logger.info("方法执行后...");
}
@AfterReturning(returning = "result", pointcut = "log()")
public void doAfterReturning(Object result) {
logger.info("执行返回值:" + result);
}
@Around("log()")
public Object trackInfo(ProceedingJoinPoint pjp) throws Throwable {
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = sra.getRequest();
String remoteHost = request.getRemoteHost();
Login loginByIp = loginDao.getLoginByIp(remoteHost);
if (loginByIp == null) {
logger.info("-------------没有登录-------------");
return Json.fail();
} else {
logger.info("-------------登录通过-------------");
}
return pjp.proceed();
}
}
package com.cun.util;
import java.util.HashMap;
import java.util.Map;
public class Json {
public static Map<String, Object> success(Object data) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", 200);
map.put("msg", "ok");
map.put("data", data);
return map;
}
public static Map<String, Object> fail() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", 400);
map.put("msg", "error");
return map;
}
}
其实这种做法是不安全的,只能拦截没有编程知识的小白群众,用户可以使用代理 ip 等技术,获取他人的 ip 去登录
参考文章:
1、这篇文章清晰了 AOP 登录拦截设计的思路
spring AOP 注解实现登录权限拦截
2、这篇文章清晰了 SpringBoot 中的 AOP 基础知识
Spring boot中使用aop详解
3、这篇文章的实验,大大减省了笔者测试SpringBoot AOP 的时间
SpringBoot中利用AOP实现拦截器效果