JAVA基于Session认证

目录

一、概念

二、认证流程

三、鉴权流程

 四、缺点

五、实现代码

5.1 项目结构

5.2 pom.xml

 5.3 application.yml

5.4 login.html

5.5 entity

5.5.1 UserDto

5.5.2 AuthenticationRequest.java

5.6 config

5.6.1 WebAppConfugurer

5.6.2 SimleAuthenticationInterceptor

5.7 service

5.7.1 AuthenticationService

5.7.2 AuthenticationServiceImpl

5.8 Controller

5.8.1 LoginController

5.8.2 UserController

5.9 效果

六、参考文章 


一、概念

        Session 是一种HTTP存储机制,目的是为无状态的HTTP提供的持久机制。所谓 Session 认证只是简单的把 User 信息存储到 Session 里,因为 SID 的不可预测性,暂且认为是安全的。这是一种认证手段。

二、认证流程

640?wx_fmt=other

  • 用户输入其登录信息

  • 服务器验证信息是否正确,并创建一个session,然后将其存储在数据库中

  • 服务器为用户生成一个sessionId,将具有sesssionId的Cookie将放置在用户浏览器中

  • 在后续请求中,会根据数据库验证sessionID,如果有效,则接受请求

  • 一旦用户注销应用程序,会话将在客户端和服务器端都被销毁

三、鉴权流程

  • 流程图如下

    • 在整个流程中有两个拦截器。
    • 第一个拦截器AuthInteceptor是为了每一次的请求的时候都先去session中取user对象,如果session中有,就放user对象到threadlocal中。这是为了业务处理的时候能直接获取用户对象。
    • 第二个拦截器AuthActionInteceptor是先看页面是否需要登录,如果不需要登录,则直接进行业务逻辑处理;如果需要登录,则判断是否已经登录(UserContext.getUser()是否为空),没有登录则重定向到登录页面,登录后是会把用户信息放到session当中的 。

 四、缺点

  • 1).sessio需要存在服务器内存中,这样就不能跨实例共享。当下一次请求被分发到另一个实例的时候,就会造成重新登录。
  • 2).在高并发情况下,session放在内存中受限于内存的大小
  • 3).session依赖于浏览器的cookie机制,对于移动客户端就很难支持。移动端使用token

五、实现代码

5.1 项目结构

5.2 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.session.test</groupId>
    <artifactId>sessiontest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sessiontest</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--thymeleaf模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <!--<version>1.4.0.RELEASE</version>-->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
        </plugins>
    </build>

</project>

 5.3 application.yml

server:
  port: 8080
spring:
  thymeleaf:
    mode: LEGACYHTML5
  main:
    #默认支持名称相同的bean的覆盖
    allow-bean-definition-overriding: true
user:
  key: SESSION_USER_KEY

5.4 login.html

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head><title>用户登录</title></head>
<body>
<form action="/login" method="post">
    姓名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br> <input type="submit" value="登录">
</form>
</body>
</html>

5.5 entity

5.5.1 UserDto

package com.session.test.sessiontest.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Set;

/**
 * @author sujm
 * @date 2021/12/22 16:50
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDto {

    private String id;

    private String username;

    private String password;

    private String fullname;

    private String mobile;

    private Set<String> authorities;
}

5.5.2 AuthenticationRequest.java

package com.session.test.sessiontest.entity;

import lombok.Data;

/**
 * @author sujm
 * @date 2021/12/22 16:49
 */
@Data
public class AuthenticationRequest {
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
}

5.6 config

5.6.1 WebAppConfugurer

package com.session.test.sessiontest.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@EnableWebMvc
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {


    @Bean
    SimpleAuthenticationInterceptor simpleAuthenticationInterceptor() {
        return new SimpleAuthenticationInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 可添加多个
        registry.addInterceptor(simpleAuthenticationInterceptor()).addPathPatterns("/r/*");
    }
}

5.6.2 SimleAuthenticationInterceptor

package com.session.test.sessiontest.config;

import com.session.test.sessiontest.entity.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
@Slf4j
public class SimpleAuthenticationInterceptor implements HandlerInterceptor {

    @Value("${user.key}")
    private String userKey;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //读取会话信息
        System.out.println(userKey);
        Object object = request.getSession().getAttribute(userKey);
        if (object == null) {
            log.info("请登录");
            writeContent(response, "请登录");
            return false;
        }
        log.info("object ={}",object);
        UserDto user = (UserDto) object;
        //请求的url
        String requestURI = request.getRequestURI();
        if (user.getAuthorities().contains("p1") && requestURI.contains("/r1")) {
            return true;
        }
        if (user.getAuthorities().contains("p2") && requestURI.contains("/r2")) {
            return true;
        }
        log.info("权限不足,拒绝访问");
        writeContent(response, "权限不足,拒绝访问");
        return false;
    }

    private void writeContent(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.print(msg);
        writer.close();
    }
}

5.7 service

5.7.1 AuthenticationService

package com.session.test.sessiontest.service;

import com.session.test.sessiontest.entity.AuthenticationRequest;
import com.session.test.sessiontest.entity.UserDto;

public interface AuthenticationService {
    UserDto authentication(AuthenticationRequest authenticationRequest);
}

5.7.2 AuthenticationServiceImpl

package com.session.test.sessiontest.service;

import com.session.test.sessiontest.entity.AuthenticationRequest;
import com.session.test.sessiontest.entity.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
@Slf4j
public class AuthenticationServiceImpl implements AuthenticationService {
    //用户信息
    private Map<String, UserDto> userMap = new HashMap<>();

    {
        Set<String> authorities1 = new HashSet<>();
        authorities1.add("p1");
        Set<String> authorities2 = new HashSet<>();
        authorities2.add("p2");
        userMap.put("zhangsan", new UserDto("1010", "zhangsan", "123", "张 三", "133443", authorities1));
        userMap.put("lisi", new UserDto("1011", "lisi", "456", "李四", "144553", authorities2));
        userMap.put("admin", new UserDto("1012", "admin", "123", "李四", "144553",null));
    }

    @Override
    public UserDto authentication(AuthenticationRequest authenticationRequest) {

        Optional.ofNullable(authenticationRequest).orElseThrow(() -> new RuntimeException("账号信息为空"));
        String password = authenticationRequest.getPassword();
        String username = authenticationRequest.getUsername();
        if (StringUtils.isEmpty(password) || StringUtils.isEmpty(username)) {
            throw new RuntimeException("用户名密码为空");
        }
        UserDto userDto = getUserDto(username);
        if (ObjectUtils.isEmpty(userDto)) {
            throw new RuntimeException("用户信息不存在");
        }
        return userDto;
    }

    public UserDto getUserDto(String username) {
        return userMap.get(username);
    }

}

5.8 Controller

5.8.1 LoginController

package com.session.test.sessiontest.controller;

import com.session.test.sessiontest.entity.AuthenticationRequest;
import com.session.test.sessiontest.entity.UserDto;
import com.session.test.sessiontest.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

/**
 * @author sujm
 * @date 2021/12/22 17:02
 */
@Controller
public class LoginController {
    @Resource
    private AuthenticationService authenticationService;

    @Value("${user.key}")
    private String userKey;

    @GetMapping("/goLogin")
    public String goLogin() {
        return "user/login";
    }

    @PostMapping(path = "/login", produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String login(AuthenticationRequest authenticationRequest, HttpSession session) {
        UserDto userDetails = authenticationService.authentication(authenticationRequest);
        System.out.println("登录" + userKey);
        session.setAttribute(userKey, userDetails);
        return userDetails.getUsername() + "登录成功";
    }

    @GetMapping(value = "logout")
    @ResponseBody
    public String logout(HttpSession session) {
        session.invalidate();
        return "退出成功";
    }
}

5.8.2 UserController

package com.session.test.sessiontest.controller;

import com.session.test.sessiontest.entity.UserDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
public class UserController {

    @Value("${user.key}")
    private String userKey;

    /*** 测试资源1 * @param session * @return
     * 登陆成功之后,直接访问这个地址测试即可
     * */
    @GetMapping(value = "/r/r1")
    public String r1(HttpSession session) {
        String fullname = null;
        Object userObj = session.getAttribute(userKey);
        if (userObj != null) {
            fullname = ((UserDto) userObj).getFullname();
        } else {
            fullname = "匿名";
        }
        return fullname + " 访问资源1";
    }

    @GetMapping(value = "/r/r2",produces = {"text/html;charset=UTF-8"})
    public String r2(HttpSession session) {
        String fullname = null;
        Object userObj = session.getAttribute(userKey);
        if (userObj != null) {
            fullname = ((UserDto) userObj).getFullname();
        } else {
            fullname = "匿名";
        }
        return fullname + " 访问资源2";
    }
}

5.9 效果

六、参考文章 

基于jwt和session用户认证的区别和优缺点_Java笔记虾-CSDN博客   基于Session的认证方式_一个人的江湖-CSDN博客_session认证  基于session和token的身份认证方案 - 开拖拉机的蜡笔小新 - 博客园

                    

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值