Authentication is based on Session, get it done! !

What is a conversation

After the user is authenticated, in order to avoid the user's authentication for each operation, the user's information can be stored in the session. The session is the mechanism provided by the system to maintain the current user's login status. Common methods are based on session and token. Way etc.

The session-based authentication method is as follows:

Its interactive process is that after the user is successfully authenticated, user-related data is generated on the server and stored in the session, and the session_id sent to the client is stored in the cookie, so that the user can verify whether the server has a session with the session_id when the client requests it. Data, when the user exits the system or the session expires and is destroyed, the client's session_id will also become invalid.

Insert picture description here

Based on the token method as shown below:

Its interactive process flow is that after the user is successfully authenticated, the server generates a token and sends it to the client. The client can put it in storage such as cookie or localStorage, and bring the token with each request, and the server will receive the token after verification. Can confirm user identity.

Picture two

Authorized data model

Authorization can be simply understood as Who performs How operations on What, including the following:

Who: The subject, the subject is generally a user, or it can be a program, which needs to access the resources in the system.

What: Resources, such as system menus, pages, buttons, code methods, system product information, system order information. System menus, pages, buttons, and code methods are all system function resources.

How: Permission permission, which specifies the user's operation permission to the resource. It does not make sense for the permission to leave the resource, such as user query permission, user add permission, call permission of a code method, modification permission of user number 001, etc., which can be known by permission Users have which operations permissions for which resources.

RBAC

Role-based access control

RBAC's role-based access control is based on role authorization. For example, if the role of the subject is the general manager, you can query corporate operation reports and query employee salary information. The access control process is as follows:

Picture three
The authorization code can be expressed as:

if(主体.hasRole("总经理角色id")) {
    
    
    查询工资
}

Resource-based access control

RBAC resource-based access control is based on resource authorization. For example, users must have the permission to query salary to query employee salary information, etc.:

Picture four

The authorization code can be expressed as:

if(主体.hasPermission("查询工资权限标识")) {
    
    
    查询工资
} 

Based on session authentication

Create project

Create a maven project and add the following dependencies to the pom.xml file

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cehcloud</groupId>
    <artifactId>security</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>
</project>

Spring container arrangement

Define ApplicationConfig.java under the config package, which corresponds to the configuration of ContextLoadListener in web.xml

package com.cehcloud.cehc.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

/**
 * @author Lenovo
 * @date 2020/8/18 21:25
 */
@Configuration
@ComponentScan(basePackages = "com.cehcloud.cehc"
                ,excludeFilters = {
    
    @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
public class ApplicationConfig {
    
    
    // 在此配置除了Controller的其它bean,比如:数据库、事务管理器、业务bean等
}

servletContext configuration

This case uses Servlet3.0 without web.xml, WebConfig.java defined under the config package, which corresponds to the DispatcherServlet configuration.

package com.cehcloud.cehc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**
 * @author Lenovo
 * @date 2020/8/18 21:29
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.cehcloud.cehc"
                ,includeFilters = {
    
    @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class WebConfig implements WebMvcConfigurer {
    
    

    @Bean
    public InternalResourceViewResolver viewResolver() {
    
    
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".html");
        return viewResolver;
    }
}

Load the Spring container

Define the Spring container initialization class SpringApplicationInitializer under the init package, which implements the WebApplicationInitializer interface, and all implementation classes of the WebApplicationInitializer interface are loaded when the Spring container starts.

package com.cehcloud.cehc.init;

import com.cehcloud.cehc.config.ApplicationConfig;
import com.cehcloud.cehc.config.WebConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * @author Lenovo
 * @date 2020/8/18 21:45
 */
public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    

    /**
     * Spring容器,相当于加载applicationContext.xml
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
    
    
        return new Class[]{
    
    ApplicationConfig.class};
    }

    /**
     * servletContext,相当于加载springmvc.xml
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
    
    
        return new Class[]{
    
    WebConfig.class};
    }

    /**
     * url-mapping
     * @return
     */
    @Override
    protected String[] getServletMappings() {
    
    
        return new String[]{
    
    "/"};
    }
}

log in page:

<%--
  Created by IntelliJ IDEA.
  User: Lenovo
  Date: 2020/8/19
  Time: 13:53
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<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>

The following configuration is added to WebConfig, which will be directly imported to the login page:

	@Override
    public void addViewControllers(ViewControllerRegistry registry) {
    
    
      registry.addViewController("/").setViewName("login");
    }

Authentication interface

The user enters the authentication page, enters the account number and password, and clicks to log in to perform identity verification.
(1) Define the authentication interface, which is used to verify the user name and password passed in.

package com.cehcloud.cehc.service;

/**
 * @author Lenovo
 * @date 2020/8/19 14:25
 */

import com.cehcloud.cehc.model.AuthenticationRequest;
import com.cehcloud.cehc.model.UserDTO;

/**
 * 认证服务
 */
public interface AuthenticationService {
    
    

    /**
     * 用户认证
     * @param authenticationRequest 用户认证请求
     * @return 认证成功的用户信息
     */
    UserDTO authentication(AuthenticationRequest authenticationRequest);
}

Authentication request structure:

package com.cehcloud.cehc.model;

import lombok.Data;

/**
 * @author Lenovo
 * @date 2020/8/19 14:27
 */
@Data
public class AuthenticationRequest {
    
    
    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;
}

After successful authentication, the user details are returned, that is, the information of the currently logged in user:

package com.cehcloud.cehc.model;

import lombok.Data;

/**
 * @author Lenovo
 * @date 2020/8/19 14:27
 */
@Data
@AllArgsConstructor
public class UserDTO {
    
    

    private String id;
    private String username;
    private String password;
    private String fullName;
    private String mobile;
}

(2) Authentication implementation class, find user information according to the user name, and verify the password, here to simulate two users:

package com.cehcloud.cehc.service.impl;

import com.cehcloud.cehc.model.AuthenticationRequest;
import com.cehcloud.cehc.model.UserDTO;
import com.cehcloud.cehc.service.AuthenticationService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Lenovo
 * @date 2020/8/19 14:35
 */
@Service
public class AuthenticationServiceImpl implements AuthenticationService {
    
    

    @Override
    public UserDTO authentication(AuthenticationRequest authenticationRequest) {
    
    
        if (authenticationRequest == null
            || StringUtils.isEmpty(authenticationRequest.getUsername())
            || StringUtils.isEmpty(authenticationRequest.getPassword())) {
    
    
            throw new RuntimeException("账号或密码为空");
        }
        UserDTO userDTO = getUserDTO(authenticationRequest.getUsername());
        if (userDTO == null) {
    
    
            throw new  RuntimeException("查不到该用户");
        }
        if (!authenticationRequest.getPassword().equals(userDTO.getPassword())) {
    
    
            throw new RuntimeException("账号或者密码错误");
        }
        return userDTO;
    }

    /**
     * 模拟用户查询
     * @param username
     * @return
     */
    public UserDTO getUserDTO(String username) {
    
    
        return userDTOMap.get(username);
    }

    /**
     * 用户信息
     */
    private Map<String, UserDTO> userDTOMap = new HashMap<>();
    {
    
    
        userDTOMap.put("zhangsan", new UserDTO());
        userDTOMap.put("lisi", new UserDTO());
    }
}

(3) Log in to the controller and process the login request. It calls AuthenticationService to complete the authentication and return the login prompt message.

package com.cehcloud.cehc.controller;

import com.cehcloud.cehc.model.AuthenticationRequest;
import com.cehcloud.cehc.model.UserDTO;
import com.cehcloud.cehc.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Lenovo
 * @date 2020/8/19 14:54
 */
@RestController
public class LoginController {
    
    

    @Autowired
    AuthenticationService authenticationService;

    @RequestMapping(value = "/login", produces = "text/plain; charset=utf-8")
    public String login(AuthenticationRequest authenticationRequest) {
    
    
        UserDTO userDTO = authenticationService.authentication(authenticationRequest);
        return userDTO.getUsername() + "登录成功";
    }
}

Realize the conversation function

(1) Increase the conversation function

​ First define a SESSION_USER_KEY in UserDTO as the key to store the login user information in the Session.

public static final String SESSION_USER_KEY = "_user" ;
​ Then modify the LoginController, after the authentication is successful, put the user information in the current session. And add the user login method, the session will be invalid when you log out.

package com.cehcloud.cehc.controller;

import com.cehcloud.cehc.model.AuthenticationRequest;
import com.cehcloud.cehc.model.UserDTO;
import com.cehcloud.cehc.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

/**
 * @author Lenovo
 * @date 2020/8/19 14:54
 */
@RestController
public class LoginController {
    
    

    @Autowired
    AuthenticationService authenticationService;

    @RequestMapping(value = "/login", produces = "text/plain; charset=utf-8")
    public String login(AuthenticationRequest authenticationRequest, HttpSession session) {
    
    
        UserDTO userDTO = authenticationService.authentication(authenticationRequest);
        // 存入session
        session.setAttribute(UserDTO.SESSION_USER_KEY, userDTO);
        return userDTO.getUsername() + "登录成功";
    }
    
    @GetMapping(value = "/logout", produces = "text/plain; charset=utf-8")
    public String logout(HttpSession session) {
    
    
        session.invalidate();
        return "退出成功";
    }
}

Guess you like

Origin blog.csdn.net/qq_44880095/article/details/112899338