Conceptos básicos de Spirng-Security: autenticación de sesión basada en SpringMVC

1. Autenticación de sesión

El proceso del método de autenticación basado en sesión consiste en que, una vez que el usuario se autentica correctamente, los datos relacionados con el usuario se generan en el servidor y se almacenan en la sesión, y el session_id enviado al cliente se almacena en la cookie, de modo que el session_id se puede verificar cuando el cliente solicita si hay datos de sesión en el servidor, para completar la verificación legal del usuario. Cuando el usuario cierra la sesión del sistema o la sesión caduca y se destruye, el session_id del cliente tampoco es válido.

API de operación relacionada con HttpSession

método significado
HttpSession getSession (creación booleana) Obtener el objeto HttpSession actual
void setAttribute (nombre de cadena, valor de objeto) Almacenar objetos en sesión
objeto getAttribute(nombre de la cadena) obtener objeto de la sesión
void removeAttribute (nombre de la cadena) eliminar el objeto en la sesión
anular invalidar () Invalidar HttpSession
Cadena getId() Obtener el ID de sesión actual

2. Crea un proyecto

Use IDEA para crear un proyecto Maven vacío, y todas las configuraciones spring y springmvc usan el método de configuración de clase java.

2.1 La estructura del proyecto maven creado es la siguiente

inserte la descripción de la imagen aquí

2.2 Dependencias relacionadas con la importación

Tenga en cuenta que el método de empaquetado debe establecerse en war package; de ​​lo contrario, no tendrá efecto configurar maven para que se ejecute con tomcat
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>day01_start</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>day01_start</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                    <!--<configuration>
                        <path>/shiro</path>
                        <port>8080</port>
                        <uriEncoding>UTF-8</uriEncoding>
                        <url>http://localhost:8080/shiro</url>
                        <server>Tomcat7</server>
                    </configuration>-->
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>

                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <configuration>
                        <encoding>utf-8</encoding>
                        <useDefaultDelimiters>true</useDefaultDelimiters>
                        <resources>
                            <resource>
                                <directory>src/main/resources</directory>
                                <filtering>true</filtering>
                                <includes>
                                    <include>**/*</include>
                                </includes>
                            </resource>
                            <resource>
                                <directory>src/main/java</directory>
                                <includes>
                                    <include>**/*.xml</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

2.3 Configuración del contenedor de resorte

// 相当于spring的主配置文件 ContextApplication.xml
@Configuration
// 加载排除controller类的包,controller交给SpringMVC来加载
@ComponentScan(basePackages = "com.mcs.security",
        excludeFilters = {
    
    @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)})
public class ApplicationConfig {
    
    
    // 在此配置除了Controller的其他bean,比如:数据库连接池、事务管理器、业务Bean
}

2.4 configuración de contexto de servlet

// SpringMVC的主配置文件,相当于springmvc.xml
@Configuration
@EnableWebMvc
// 只加载controller下的包
@ComponentScan(basePackages = "com.mcs.security"
            ,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/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

2.5 Cargar archivos de configuración spring y springmvc

Este archivo es equivalente al archivo web.xml

public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    
    // 加载spring容器,相当于加载ApplicationContext.xml
    @Override
    protected Class<?>[] getRootConfigClasses() {
    
    
        return new Class<?>[] {
    
     ApplicationConfig.class };
    }

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

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

2.6 Realizar la función de autenticación de inicio de sesión

Defina la página de autenticación login.jsp en webapp/WEB-INF/views

<%@ 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>

Al mismo tiempo, vincule la configuración de URL de la ruta raíz a la página de inicio de sesión y configúrela en WebConfig.java

@Override
    public void addViewControllers(ViewControllerRegistry registry) {
    
    
        // 将/直接重定向到login页面
        registry.addViewController("/").setViewName("login");
    }

2.7 Configurar tomcat en maven y probar

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

3. Función de autenticación de inicio de sesión

Iniciar sesión no es más que verificar si el nombre de usuario y la contraseña se corresponden entre sí. Primero, no se conecte a la base de datos y simule datos para la verificación.

3.1 Objeto de usuario actual y objeto de información de usuario

AuthenticationRequest.javaSe utiliza para encapsular el formulario enviado

@Data 
// 认证请求结构
public class AuthenticationRequest {
    
    
    private String username;
    private String password;
}

Información básica del usuario

@Data // 构造所有参数的getAndSet方法
@AllArgsConstructor // 拥有所有参数的构造方法
// 当前登录的用户信息
public class UserDto {
    
    
    public static final String SESSION_USER_KEY = "_user";

    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;

    // 权限信息
    private Set<String> authorities;
}

3.2 Interfaz de procesamiento de solicitud de autenticación de inicio de sesión y clase de implementación

@Service
public interface AuthenticationService {
    
    

    UserDto authentication(AuthenticationRequest authenticationRequest);
}

Simule datos, consulte datos y verifique

@Service
public class AuthenticationServiceImpl implements AuthenticationService{
    
    
    // 模拟数据库用户信息
    private Map<String, UserDto> userDtoMap = new HashMap<>();
    {
    
    
        Set<String> zs = new HashSet<>();
        zs.add("p1");
        Set<String> ls = new HashSet<>();
        ls.add("p2");
        userDtoMap.put("zhangsan", new UserDto("1010", "zhangsan", "123", "张三", "12345", zs));
        userDtoMap.put("lisi", new UserDto("1011", "lisi", "123", "张三", "12345", ls));
    }
    // 模拟数据库查询功能
    public UserDto getUserDto(String name) {
    
    
        UserDto userDto = userDtoMap.get(name);
        return userDto;
    }

    @Override
    public UserDto authentication(AuthenticationRequest authenticationRequest) {
    
    
        if (authenticationRequest.getPassword() == null ||
                    authenticationRequest.getPassword() == null) {
    
    
            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;
    }
}

3.3 controlador para control de solicitudes

@Controller
@ResponseBody
public class loginController {
    
    

    @Autowired
    AuthenticationService authenticationService;
    // produces设置返回类型为文本类型,同时指定字符集
    @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.getFullname() + "登录成功";
    }
}

3.4 Ejecute la función de inicio de sesión de prueba

inserte la descripción de la imagen aquí

4. Realice la función de conversación.

Guardamos la información de la sesión después de un inicio de sesión exitoso. Ahora simulamos dos recursos, permitimos el acceso de los usuarios registrados y mostramos quién accede a qué recurso.

Simule dos solicitudes de recursos en la clase de configuración del controlador y configure además el cierre de sesión.

    @RequestMapping(value = "/r/r1", produces = {
    
    "text/plain;charset=UTF-8"})
    public String test(HttpSession session) {
    
    
        String fullname = null;
        Object object = session.getAttribute(UserDto.SESSION_USER_KEY);
        if (null == object) {
    
    
            fullname = "匿名";
        } else {
    
    
            fullname = ((UserDto)object).getFullname();
        }
        return fullname + "访问资源r1";
    }

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

    @RequestMapping(value = "/logout", produces = {
    
    "text/plain;charset=UTF-8"})
    public String logout(HttpSession session) {
    
    
        // 使session失效
        session.invalidate();
        return "退出成功";
    }

Prueba
inserte la descripción de la imagen aquí
Si ha iniciado sesión, mostrará que el registrante ha accedido al recurso, y si no hay nadie, mostrará que la persona anónima ha accedido al recurso.

5. Realizar la función de autorización

La función de autorización significa que diferentes personas pueden acceder a diferentes recursos. Los usuarios comunes no pueden acceder a los recursos del administrador porque no tienen esta autoridad. Establecemos la autoridad del usuario y juzgamos si hay autoridad o no al acceder. Esta es la realización de la autorización.

Al simular datos de usuario, se ha inicializado la información relacionada con los permisos de usuario.
inserte la descripción de la imagen aquí
¿Cómo juzgar si el usuario tiene permiso al acceder? Usamos el interceptor de springmvc para interceptar la solicitud y juzgar si hay permiso. Hemos configurado: Zhang San tiene permiso para acceder a r1 y Li Si tiene permiso para acceder r2, y luego vea cómo lograrlo.

Defina el interceptor SimpleAuthenticationInterceptor en el paquete interceptor para implementar la interceptación de autorización:
1. Verifique si el usuario ha iniciado sesión
2. Verifique si el usuario tiene derechos de operación

@Component
public class SimpleAuthenticationInterceptor implements HandlerInterceptor {
    
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        // 读取会话信息
        Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);
        if(object == null) {
    
    
            writeContent(response, "请登录");
        }
        UserDto userDto = (UserDto)object;
        // 获取请求得url
        String requestRUL = request.getRequestURI();
        if (userDto.getAuthorities().contains("p1") && requestRUL.contains("/r1")) {
    
    
            return true;
        }
        if (userDto.getAuthorities().contains("p2") && requestRUL.contains("/r2")) {
    
    
            return true;
        }
        writeContent(response, "权限不足,拒绝访问");
        return false;
    }

    // 响应数据给客户端
    private void writeContent(HttpServletResponse response, String msg) throws Exception{
    
    
        response.setContentType("text/html;charset=utf-8");
        // getWriter获取一个输出流
        PrintWriter writer = response.getWriter();
        // 将数据打印再客户端
        writer.println(msg);
        writer.close();
    }
}

El interceptor está configurado, también necesitamos WebConfig.javaconfigurar el interceptor en el archivo de configuración de springmvc

  // 配置拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
    // 只拦截了/r/下的请求
        registry.addInterceptor(simpleAuthenticationInterceptor).addPathPatterns("/r/**");
    }

Prueba
1, estado no conectado
inserte la descripción de la imagen aquí
2, Zhang San accediendo al recurso r1
inserte la descripción de la imagen aquí
3, Zhang San accediendo al recurso r2
inserte la descripción de la imagen aquí
Li Si es el mismo y ya no se muestra

Resumir

Usamos el interceptor de springmvc para implementar la interceptación de las solicitudes de los usuarios y la autorización de permisos simulados. Usar un marco de seguridad de terceros será más fácil de implementar. El siguiente capítulo es un inicio rápido del marco de seguridad de Spring.

Supongo que te gusta

Origin blog.csdn.net/qq_44660367/article/details/109515421
Recomendado
Clasificación