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 的不可预测性,暂且认为是安全的。这是一种认证手段。

二、认证流程

JAVA基于Session认证_第1张图片

  • 用户输入其登录信息

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

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

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

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

三、鉴权流程

  • 流程图如下

    JAVA基于Session认证_第2张图片

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

 四、缺点

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

五、实现代码

5.1 项目结构

JAVA基于Session认证_第3张图片

5.2 pom.xml



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.2
         
    
    com.session.test
    sessiontest
    0.0.1-SNAPSHOT
    sessiontest
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
            
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
            
                org.apache.maven.plugins
                maven-resources-plugin
                3.1.0
            
        
    


 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



用户登录

姓名:
密码:

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 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 userMap = new HashMap<>();

    {
        Set authorities1 = new HashSet<>();
        authorities1.add("p1");
        Set 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 效果

  • 启动访问 http://127.0.0.1:8080/goLogin

    JAVA基于Session认证_第4张图片


    两个用户 zhhangsan/123,lisi/456
  • 登陆成功

    JAVA基于Session认证_第5张图片

  • 登陆成功之后,直接访问http://127.0.0.1:8080/r/r1或http://127.0.0.1:8080/r/r2有无权限截图如下

    JAVA基于Session认证_第6张图片


    zhangsan有r1的权限,lisi有r2的权限

六、参考文章 

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

                    

你可能感兴趣的:(认证,java,后端,html5)