1. 程式人生 > 其它 >前後端分離實現登陸攔截

前後端分離實現登陸攔截

登入攔截的實現有以下三種方式

一、同步的方式

1、登入時把資訊儲存在session中

    @PostMapping("login")
    public String login(String name, String password, HttpSession session) {
        //判斷使用者名稱或密碼是否為空
        if (null == name || "" == name || null == password || "" == password) {
            session.setAttribute("name", name);
            session.setAttribute(
"name", password); session.setAttribute("msg", "使用者名稱或密碼為空"); System.out.println("使用者名稱或密碼為空"); return "redirect:/login.jsp"; } Employee employee = employeeService.login(name, password); if (Objects.isNull(employee)) { session.setAttribute(
"name", name); session.setAttribute("name", password); session.setAttribute("msg", "使用者名稱或密碼錯誤"); System.out.println("使用者名稱或密碼錯誤"); return "redirect:/login.jsp"; } session.setAttribute("employee", employee); System.out.println("success");
return "redirect:/list"; }

2、定義攔截器,判斷是否登入

 登陸攔截器

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {

        Object employee = request.getSession().getAttribute("employee");
        if (employee==null){
            System.out.println("沒有登陸");
            request.getSession().setAttribute("msg","\uD83C\uDF36\uD83D\uDC14先登入");
            response.sendRedirect("login.jsp");
            return false;
        }
        return true;
    }
}        

3、沒有登入時重定向至登入頁(同步的方式中重定向是成功的)

二、非同步的方式——前端頁面在專案中

  程式碼同方式三

1、登入時把資訊儲存在session中

2、定義攔截器,判斷是否登入

3、沒有登入時,給前端返回統一的狀態碼(拋異常),讓前端跳轉(非同步的方式,重定向是無效的)

三、非同步的方式——前端頁面不在專案中(前後端分離)

我們要知道的事:

  在我們編寫前端的時候,使用了vue,可能就沒有了jQuery,沒有了jQuery就證明沒有了$.get、$.post、$.ajax,因此想要傳送請求,就只能使用原生的ajax,但是使用原生的ajax程式碼太多不夠優雅,所以此時我們需要依賴另一個ajax請求的封裝庫Axios。

注意:

  這種方式預設是不攜帶cookie的,每一次的請求都會建立一個新的會話(新建立一個session),不攜帶cookie就無法根據cookie中session的ID確定要獲取的session

  前兩種方式中session的獲取預設是沒有問題的,因為前兩種預設攜帶cookie

  所以第三種方式的實現是在第二種方式的基礎上,讓請求攜帶cookie

1、讓請求攜帶cookie

第一步:後臺(Java)允許攜帶

例如在使用跨域資源共享(CORS)方式解決跨域問題時,程式碼如下

配置類的編寫方式

    /**
     * 配置解決跨域問題
     * 等級於配置檔案中的<mvc:cors></mvc:cors>
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*")
                .allowedMethods("*")
                //是否允許攜帶cookie
                .allowCredentials(true);
    }

配置檔案的編寫方式
<!-- 解決API介面跨域問題配置 Spring MVC 版本必須是 4.2 及以上 --> <mvc:cors> <mvc:mapping path="/**" allowed-origins="*" allowed-methods="POST, GET, OPTIONS, DELETE, PUT" allowed-headers="Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With" allow-credentials="true" max-age="3600" /> </mvc:cors>

第二步:前端設定攜帶

在自定義axios時可以設定攜帶cookie

let myaxios = axios.create({
    baseURL:'http://localhost:8080/',
    //設定攜帶cookie
    withCredentials:true,
    timeout:5000
});

2、登入時把資訊儲存在session中

    @PostMapping("doLogin")
    public AxiosResult<Void> doLogin(@RequestBody Map<String,String>map, HttpSession session){
        System.out.println(map);
        String phone = map.get("phone");
        String code = map.get("code");
        String s = stringRedisTemplate.opsForValue().get(phone);
        if (s.equals(code)) {
            Employee employee = employeeService.findByPhone(phone);
            //將登陸資訊放入session
            session.setAttribute("user",employee);
            //清除
            stringRedisTemplate.delete(phone);
            System.out.println(AxiosResult.success().getData());
            return AxiosResult.success();
        }
        throw new MyLoginException(AxiosStatus.CODE_CHECK_ERROR);
    }

3、定義攔截器,判斷是否登入

 登陸攔截器

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {

        Object user = request.getSession().getAttribute("user");
        if (user==null){
            System.out.println("沒有登陸");
            throw new MyLoginException(AxiosStatus.NOT_LOGIN);
        }
        return true;
    }
}

4、沒有登入時,給前端返回統一的狀態碼(拋異常),讓前端跳轉

註解所需要的jar自行import

狀態碼的列舉類
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum AxiosStatus {

    OK(2000,"操作成功"),
    ERROR(5000,"操作失敗"),
    //登入相關狀態碼
    PHONE_NOT_FOUND(3000,"手機號錯誤"),
    USER_NOT_ACTIVE(3001,"使用者未啟用"),
    CODE_CHECK_ERROR(3002,"驗證碼錯誤"),
    NOT_LOGIN(4004,"登入過期,請重新登入"),
    ;
    private int status;

    private String message;

}

自定義異常
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class MyLoginException extends RuntimeException{

    private AxiosStatus axiosStatus;
    
}

處理異常類

import com.shangma.cn.common.AxiosResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class MyHandler {

    @ExceptionHandler(MyLoginException.class)
    public AxiosResult<Void> myHandler(MyLoginException e){
        System.out.println(e.getAxiosStatus());
        return AxiosResult.error(e.getAxiosStatus());
    }
}

登入攔截後的跨域問題  

  當自己新增攔截器時,如果你的請求滿足了攔截器,請求繼續向下執行,沒有問題,但是當你的請求不滿足攔截器時,將會出現跨域問題,哪怕你解決了跨域問題都未必有效。

解決思想:

  在自定義攔截器前,解決跨域問題

操作方式

1、自定義Filter(Filter比spring mvc中的攔截器更早地執行)

  過濾的是servlet的請求,我們的攔截器是spring mvc的攔截器,想要進入spring mvc的攔截器,前提是要進入spring mvc,進入springmvc 是通過dispatcherServler,滿足dispatcherServler中設定的請求才能進入,恰巧Filter可以對servlet進行攔截

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

 第一種解決跨域問題的方式    全域性解決

//進入springmvc之前,處理跨域問題 攔截所有請求
@WebFilter("/*")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /**
     * 在過濾器中解決跨域問題
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("過濾器執行了");
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        //設定跨域請求
        String origin = req.getHeader("Origin");
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if(origin == null) {
            origin = req.getHeader("Referer");
        }
        // 允許指定域訪問跨域資源
        response.setHeader("Access-Control-Allow-Origin", origin);
        // 允許客戶端攜帶跨域cookie,此時origin值不能為“*”,只能為指定單一域名
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Cookie,token");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        filterChain.doFilter(req, response);

    }

    @Override
    public void destroy() {

    }
}

2、修改spring mvc中的跨域過濾器的順序

  第一步:向父容器中新增一個元件CorsFilter

配置類的寫法
  
  /**
     * 向父容器中新增Filter,解決跨域問題完美解決二(區域性)
     * @return
     */
    @Bean
    public CorsFilter corsFilter(){
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);
        CorsFilter corsFilter = new CorsFilter(corsConfigurationSource);
        return corsFilter;
    }

  第二步:掛載到攔截器上

    在web.xml的配置類中使用DelegatingFilterProxy代理,指定定義的過濾器即可

    /**
     * 掛載到攔截器上,解決跨域問題方式二
     * @return
     */
    @Override
    protected Filter[] getServletFilters() {
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetBeanName("corsFilter");
        Filter[] filters = new Filter[]{proxy};
        return filters;
    }