SpringBoot最简单的单点登录并支持跨域的实现

本篇文章,使用了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,目录结构如下:


image.png

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保存起来


image.png

2,登录按钮11111,将sessionId带回给服务器


image.png

3,后台代码,证明是同一个session
image.png

由此可见,这好像实现类了单点登录功能,并且支持了跨域,这里选择请求头而不用cookie,是因为手机App这种是没有cookie滴。。。。。

谢谢你,看完了我的文章,写的比较烂,毕竟是理科生,没什么文采。

祝好~

你可能感兴趣的:(SpringBoot最简单的单点登录并支持跨域的实现)