实现前后端session共享

目录

1、如何实现session共享

1.1、修改shiro的配置类

2、解决前端不支持cookie的效果

2.1、修改登录的接口

2.2、修改前端登录办法

2.3、修改前端main.js文件

2.4、重写DefaultWebSessionManager的方法

2.5、修改shiro配置类

2.6、修改shiroFilter过滤器

1、如何实现session共享

session默认存储再各自服务的内存中,我们可以采用让session统一存储再redis中来解决不共享问题。

疯狂的蛋糕的依赖。---提供了redis存储session的类。

1.1、修改shiro的配置类

@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、解决前端不支持cookie的效果

原因: 默认DefaultWebSessionManager它只接受Cookie中存储的JsessionId. 查询发现再redis中不存在对应的key.

客户发送请求时,再请求头中携带sessionId, 然后重写DefaultWebSessionManager中getSessionId()的方法。

解决:

1. 把sessionId放入请求头。

2. 重写getSessionId方法获取请求头中的sessionID

2.1、修改登录的接口

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、修改前端登录办法

 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、修改前端main.js文件

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

2.4、重写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、修改shiro配置类

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

2.6、修改shiroFilter过滤器

我们发现跨域请求,会发送两个请求:第一个OPTIONS请求,第二个请求是真实的请求。

OPTIONS请求:先头部队。

所以我们对OPTIONS请求都要放行

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Flask 中,可以使用 Flask-Session 扩展来实现 session 的交互。下面是实现步骤: 1. 安装 Flask-Session 扩展: ``` pip install Flask-Session ``` 2. 在 Flask 应用中初始化扩展: ```python from flask import Flask from flask_session import Session app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key' app.config['SESSION_TYPE'] = 'filesystem' sess = Session() sess.init_app(app) ``` 3. 在前端页面中发送请求时,需要将 session_id 发送至后端: ```html <form method="POST" action="/login"> <input type="text" name="username" placeholder="Username"> <input type="password" name="password" placeholder="Password"> <input type="hidden" name="session_id" value="{{session_id}}"> <button type="submit">Login</button> </form> ``` 4. 在后端接收请求时,获取 session_id 并进行操作: ```python from flask import request, session @app.route('/login', methods=['POST']) def login(): username = request.form['username'] password = request.form['password'] session_id = request.form['session_id'] # 验证用户名和密码 if username == 'admin' and password == '123456': # 将用户信息存储到 sessionsession['user'] = {'username': username, 'password': password} return 'Login success!' else: return 'Login failed!' ``` 5. 在前端页面中获取 session 中存储的信息: ```html {% if session.get('user') %} <p>Welcome, {{session['user']['username']}}!</p> {% else %} <p>Please login first.</p> {% endif %} ``` 以上就是使用 Flask-Session 实现 session 交互的步骤。需要注意的是,Flask-Session 默认将 session 存储在服务器的文件系统中,也可以使用其他方式存储,例如 Redis、Memcached 等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值