前后端分离实现登陆拦截


 

登录拦截的实现有以下三种方式

一、同步的方式

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

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM