Realize front-end and back-end session sharing

Table of contents

1. How to implement session sharing

1.1. Modify shiro’s configuration class

2. Solve the problem of the front-end not supporting cookies

2.1. Modify the login interface

2.2. Modify the front-end login method

2.3. Modify the front-end main.js file

2.4. Method of overriding DefaultWebSessionManager

2.5. Modify shiro configuration class

2.6. Modify the shiroFilter filter

1. How to implement session sharing

By default, sessions are stored in the memory of their respective services. We can solve the problem of non-sharing by allowing sessions to be stored uniformly in redis.

Crazy cake dependence. --- Provides a class for redis to store sessions.

1.1. Modify shiro’s configuration class

@Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm());
        //设置缓存管理器
        securityManager.setCacheManager(redisCacheManager());
        //session管理
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }
    
    @Bean
    public SessionManager sessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(sessionDAO());//sessionDao用于操作session对象,在容器中对对象session进行CRUD操作
        return sessionManager;
    }

    @Bean
    public SessionDAO sessionDAO(){
        //该类会对对象session进行CRUD操作
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        sessionDAO.setRedisManager(redisManager());
        return sessionDAO;
    }

    //redis缓存管理器
    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        //redisCacheManager.setPrincipalIdFieldName("userId");
        return redisCacheManager;
    }

    //redis管理器
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("192.168.232.166"+":6379");
        redisManager.setDatabase(1);
        return redisManager;
    }

    @Bean
    public MyRealm myRealm(){
        MyRealm myRealm=new MyRealm();
        //设置密码加密器
        myRealm.setCredentialsMatcher(credentialsMatcher());
        return myRealm;
    }

   @Bean
    public HashedCredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(5);
        return credentialsMatcher;
    }

2. Solve the problem of the front-end not supporting cookies

Reason: The default DefaultWebSessionManager only accepts the JsessionId stored in Cookie. The query found that the corresponding key does not exist in redis.

When the client sends a request, it carries the sessionId in the request header, and then overrides the getSessionId() method in DefaultWebSessionManager.

solve:

1. Put the sessionId into the request header.

2. Override the getSessionId method to obtain the sessionID in the request header

2.1. Modify the login interface

package com.lx.controller;

import com.lx.vo.LoginVo;
import com.lx.vo.Result;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * @program: springboot-shiro
 * @description:前后端分离
 * @author: 
 * @create: 2023-07-10 16:51
 **/
@Controller
/*@CrossOrigin
 origins:允许哪些跨域访问该接口 allowedHeaders:允许携带哪些头信息的请求访问 methods:允许哪些请求方式跨域请求接口*/
public class LoginPlusController {

    @PostMapping("/loginPlus")
    @ResponseBody
    public Result login(@RequestBody LoginVo loginVo) {
        System.out.println(loginVo);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getUsername(), loginVo.getPassword());
        try {
            subject.login(token);
            return new Result(200,"登录成功",subject.getSession().getId());//携带当前会话的id
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(500,"账号或密码错误",null);
        }
    }
}

2.2. Modify the front-end login method

 methods:{
    submitForm(){
      console.log(this.form)
      this.$http.post("http://localhost:8080/loginPlus",this.loginForm).then(result=>{
        if (result.data.code==200){
          this.$message.success("登录成功")
          sessionStorage.setItem("token",result.data.data())//存在sessionStorage中,浏览器关闭token就销毁了
          this.$router.push("/product")//路由跳转
        }else {
          this.$message.error("账号或密码错误")
        }
        console.log(result)
      })
    }

2.3. Modify the front-end main.js file

//设置axios的请求拦截器
axios.interceptors.request.use(config=>{
  //从sessionStorage中获取token值
  var item = sessionStorage.getItem("token");
  if (item){
    config.headers.token=item;
  }
  return config;
})

2.4. Method of overriding DefaultWebSessionManager

package com.lx.realm;


import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

/**
 * @program: springboot-shiro
 * @description:
 * @author: 
 * @create: 2023-07-11 15:08
 **/
public class MyWebSessionManager extends DefaultWebSessionManager {
    private static final String AUTHORIZATION = "token";
    private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        //获取请求头中名称为token的内容
        String id = WebUtils.toHttp(request).getHeader("token");
        if (!StringUtils.isEmpty(id)) { //如果存在该token
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "Stateless request");
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        } else {
            //从cookie中获取sessionId.
            return super.getSessionId(request, response);
        }
    }
}

2.5. Modify shiro configuration class

@Bean
    public SessionManager sessionManager(){
        //DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        MyWebSessionManager sessionManager = new MyWebSessionManager();//修改为我们自己定义的SessionManager类
        sessionManager.setSessionDAO(sessionDAO());//sessionDao用于操作session对象,在容器中对对象session进行CRUD操作
        return sessionManager;
    }

2.6. Modify the shiroFilter filter

We found that for cross-domain requests, two requests will be sent: the first OPTIONS request, and the second request is the real request.

OPTIONS request: vanguard.

So we all allow OPTIONS requests.

package com.lx.filter;

import com.alibaba.fastjson.JSON;
import com.lx.vo.Result;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;

/**
 * @program: springboot-shiro
 * @description:
 * @author: 
 * @create: 2023-07-11 16:48
 **/
public class LoginFilter extends FormAuthenticationFilter {
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        response.setContentType("appliation/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        Result result = new Result(401, "未登录", null);
        String jsonString = JSON.toJSONString(result);
        writer.print(jsonString);
        writer.flush();
        writer.close();
        return false;
    }


    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        HttpServletRequest request1 = (HttpServletRequest) request;
        //获取请求方式
        String method = request1.getMethod();
        if ("OPTIONS".equals(method)){
            return true;
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }
}

Guess you like

Origin blog.csdn.net/weixin_54065960/article/details/131659144