本篇文章,使用了Vue.js和axios.js做异步请求,我们知道异步请求是不支持跨域的,为了解决这个问题已经有了很多实现方案,本例子使用Cros方案,cros是W3C出的标志跨域请求协议,文章文字描述比较少,都是直接贴代码,大家可以直接复制。
原理:模拟使用Cookie保存sessionId的功能。
1,登录时由tomcat服务器将sessionId放到请求头,发送给客户端;
2,客户端将请求头的sessionId保存到浏览器的sessionStorage中;
3,客户端登录后的每次请求都以同样的请求头将sessionId带回给服务器。
最后有案例演示的图片,使用的是sublime text3运行login.html文件,用来模拟两个服务器之间发请求,由sublime服务器来请求tomcat服务器,来看是否session一致的。
需要有Redis和Mysql数据库。
hosts文件修改如下:
127.0.0.1 www.liyucheng.com
127.0.0.1 test1.liyucheng.com
127.0.0.1 test2.liyucheng.com
127.0.0.1 test3.liyucheng.com
127.0.0.1 test4.liyucheng.com
127.0.0.1 test5.liyucheng.com
127.0.0.1 test6.liyucheng.com
127.0.0.1 test7.liyucheng.com
127.0.0.1 test8.liyucheng.com
127.0.0.1 test9.liyucheng.com
1,目录结构如下:
2,pom.xml中jar包依赖如下:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.6.RELEASE
com.example
springsession
0.0.1-SNAPSHOT
springsession
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.session
spring-session-core
org.springframework.session
spring-session-data-redis
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-data-redis
mysql
mysql-connector-java
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.1.1
org.springframework.boot
spring-boot-maven-plugin
3,application.properties文件
spring.session.store-type=redis
server.servlet.session.timeout=1800
#spring.session.hazelcast.flush-mode=on-save
spring.session.redis.namespace=spring.session
spring.redis.host=192.168.1.105
spring.redis.password=
spring.redis.port=6379
spring.datasource.url=jdbc:mysql://192.168.1.105:3306/test
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:mapper/*.xml
#debug=true
server.port=8080
#server.servlet.context-path=/spring_session
4,Session的配置类如下:
package com.example.springsession.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.web.http.CookieHttpSessionIdResolver;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.session.web.http.HeaderHttpSessionIdResolver;
/**
* spring session 配置类
*/
@Configuration
public class MySpringSessionConfig {
// @Bean
public DefaultCookieSerializer setDefaultCookieSerializer() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setDomainName("liyucheng.com");
return cookieSerializer;
}
/**
* 使用请求头作为会话认证
* @return
*/
@Bean
public HeaderHttpSessionIdResolver setHeaderHttpSessionIdResolver() {
return HeaderHttpSessionIdResolver.authenticationInfo();
}
// @Bean
public CookieHttpSessionIdResolver setCookieHttpSessionIdResolver() {
return new CookieHttpSessionIdResolver();
}
}
5,controller的内容如下:
package com.example.springsession.controller;
import com.example.springsession.pojo.Account;
import com.example.springsession.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
import java.util.List;
@Controller
@CrossOrigin(allowCredentials = "true", allowedHeaders = {"Authentication-Info", "content-type"}, exposedHeaders = {"Authentication-Info"})
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@ResponseBody
@RequestMapping("/add")
public String insert(Account account) {
account = accountService.add(account);
return "success " + account;
}
@ResponseBody
@RequestMapping("/login")
public Boolean selectByPrimary(@RequestBody Account account, HttpSession session) {
boolean success = accountService.login(account);
if(success) {
session.setAttribute("account", account);
}
System.out.println(session.getId());
return success;
}
@ResponseBody
@RequestMapping("/search")
public List search(HttpSession session) {
System.out.println(session.getId());
if(session.getAttribute("account") == null) {
return null;
}
List accountList = accountService.search();
return accountList;
}
}
6,service内容如下:
6.1,接口
package com.example.springsession.service;
import com.example.springsession.pojo.Account;
import java.util.List;
public interface AccountService {
Account add(Account account);
boolean login(Account account);
List search();
}
6.2实现类
package com.example.springsession.service.impl;
import com.example.springsession.mapper.AccountMapper;
import com.example.springsession.pojo.Account;
import com.example.springsession.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
public Account add(Account account) {
accountMapper.insert(account);
return account;
}
@Override
public boolean login(Account loginAccount) {
Account account = accountMapper.selectByName(loginAccount.getName());
if(account.getPasswd().equals(loginAccount.getPasswd())) {
account.setPasswd("");
loginAccount = account;
return true;
}
return false;
}
@Override
public List search() {
List accountList = accountMapper.select();
return accountList;
}
}
7,mapper内容如下:
7.1,mapper接口
package com.example.springsession.mapper;
import com.example.springsession.pojo.Account;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface AccountMapper {
int insert(Account account);
Account selectByPrimary(int id);
Account selectByName(String name);
List select();
}
7.2,mapper配置文件
insert into account (id, name, passwd) value (#{id }, #{name }, #{passwd })
8,pojo内容如下:
package com.example.springsession.pojo;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private String name;
private String passwd;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
}
9,数据库表结构如下:
create table account (
`id` int primary key auto_increment,
`name` varchar(255) not null unique,
`passwd` varchar(255) not null
);
10,测试用的Html如下:
登陆页面
以上便是这个案例的,所有内容了。
知识要点是:
1,使用@CrossOrigin来支持跨域,配置好用户可以可以获取到的请求头Authentication-Info,以及我们系统支持的请求头Authentication-Info和content-type,并设置接受cookie为true。
@CrossOrigin(allowCredentials = "true", allowedHeaders = {"Authentication-Info", "content-type"}, exposedHeaders = {"Authentication-Info"})
2,在session的配置类中指定使用HeaderHttpSessionIdResolver作为session的认证
/**
* 使用请求头作为会话认证
* @return
*/
@Bean
public HeaderHttpSessionIdResolver setHeaderHttpSessionIdResolver() {
return HeaderHttpSessionIdResolver.authenticationInfo();
}
3,登录后我们系统会发送一个Authentication-Info请求头,这时需要客户端自己将其保存起来,然后在每次发起请求时,将其带回给服务器,就可以做到session的效果
sessionStorage.setItem('authentication-info', token);
axios.defaults.headers.common['authentication-info'] = sessionStorage.getItem('authentication-info');
本案例使用Vue的axios发起异步请求,将sessionId保存起来,设置axios请求每次都带上这个信息,起到了支持跨域的session会话。
以下是本次案例的演示效果图:
1,登录按钮,跨域请求,得到了sessionId保存起来
2,登录按钮11111,将sessionId带回给服务器
3,后台代码,证明是同一个session
由此可见,这好像实现类了单点登录功能,并且支持了跨域,这里选择请求头而不用cookie,是因为手机App这种是没有cookie滴。。。。。
谢谢你,看完了我的文章,写的比较烂,毕竟是理科生,没什么文采。
祝好~