1. 程式人生 > >據說是springboot下實現cas的單點登入(但是我總感覺是MVC)----基於前後臺分離的

據說是springboot下實現cas的單點登入(但是我總感覺是MVC)----基於前後臺分離的

一、前言

前後端分離開發是目前軟體開發的主流,大大提高了開發效率 
但也帶來了很多不方便之處。

1、優點: 
① 傳統全棧開發的 MVC 模式將不適合,後臺採取 MVP 面向介面程式設計,耦合度大大降低

2、缺點: 
① 跨域問題不勝其擾

3、原則: 
① 一個合格的後臺應全力負責業務邏輯 
② 前端不要參與過多的業務邏輯,專注於網頁的視覺建設 
否則專案耦合度高、網站的安全性低

二、思路

學過計算機網路的,都知道,每個人的電腦的 ip 地址是全球唯一的, 
我們可以利用 ip 地址在資料庫中的記錄中的 查詢、增加、刪除,來進行 攔截、登入、登出 
使用 AOP 程式設計,對指定的方法進行登入攔截

三、程式碼

下面以個人最近開發的一個校園外賣網站的後臺程式碼為例(待續),抽取分享相關的程式碼

1、程式碼結構

 


2、登入實體 Login.java

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;
    }

}

3、Dao層 LoginDao.java

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<Login, Integer>{

    // 注意: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);

}

4、安全控制 MySecurity.java

構思最為長久的地方

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();
    }

}

5、通用返回值工具類簡單設計

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實現攔截器效果
--------------------- 
作者:larger5 
來源:CSDN 
原文:https://blog.csdn.net/larger5/article/details/80289740?utm_source=copy 
版權宣告:本文為博主原創文章,轉載請附上博文連結!