Spirng-Security Basics--Session Authentication Based on SpringMVC

1. Session authentication

The process of the session-based authentication method is that after the user is successfully authenticated, the 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 session_id can be verified when the client requests Whether there is session data in the server, so as to complete the legal verification of the user. When the user logs out of the system or the session expires and is destroyed, the session_id of the client is also invalid.

HttpSession related operation API

method meaning
HttpSession getSession(Boolean create) Get the current HttpSession object
void setAttribute(String name,Object value) Store objects in session
object getAttribute(String name) get object from session
void removeAttribute(String name) remove the object in the session
void invalidate() Invalidate HttpSession
String getId() Get the current sessionID

2. Create a project

Use IDEA to create an empty Maven project, and the spring and springmvc configurations all use the java class configuration method.

2.1 The created maven project structure is as follows

insert image description here

2.2 Import related dependencies

Note that the packaging method must be set to war package, otherwise it will not take effect to configure maven to run with 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 Spring container configuration

// 相当于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 servlet context configuration

// 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 Load spring and springmvc configuration files

This file is equivalent to the web.xml file

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 Realize the login authentication function

Define the authentication page login.jsp under 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>

At the same time, bind the root path url configuration to the login page and configure it in WebConfig.java

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

2.7 Configure tomcat in maven and test

insert image description here
insert image description here

3. Login authentication function

Logging in is nothing more than verifying whether the user name and password correspond to each other, without connecting to the database first, and simulating data for verification.

3.1 Current user object and user information object

AuthenticationRequest.javaUsed to encapsulate the submitted form

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

Basic user information

@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 Login authentication request processing interface and implementation class

@Service
public interface AuthenticationService {
    
    

    UserDto authentication(AuthenticationRequest authenticationRequest);
}

Simulate data, query data and verify

@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 controller for request control

@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 Run the test login function

insert image description here

4. Realize the conversation function

We saved the session information after successful login. Now we simulate two resources, let logged-in users access, and show who accesses which resource.

Simulate two resource requests in the controller configuration class, and configure logout in addition.

    @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 "退出成功";
    }

Test
insert image description here
If you have logged in, it will show that the registrant has accessed the resource, and if there is no one, it will show that the anonymous person has accessed the resource

5. Realize the authorization function

The authorization function means that different people can access different resources. Ordinary users cannot access the administrator's resources because they do not have this authority. We set the user's authority and judge whether there is authority or not when accessing. This is the realization of authorization.

When simulating user data, information related to user permissions has been initialized.
insert image description here
How to judge whether the user has permission when accessing? We use the interceptor of springmvc to intercept the request and judge whether there is permission. We have set up: Zhang San has the permission to access r1, and Li Si has the permission to access r2 , and then see how to achieve.

Define the SimpleAuthenticationInterceptor interceptor under the interceptor package to implement authorization interception:
1. Verify whether the user is logged in
2. Verify whether the user has operation rights

@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();
    }
}

The interceptor is configured, we also need to WebConfig.javaconfigure the interceptor in the configuration file of springmvc

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

Test
1, not logged in status
insert image description here
2, Zhang San accessing resource r1
insert image description here
3, Zhang San accessing resource r2
insert image description here
Li Si is the same and no longer displayed

Summarize

We use the interceptor of springmvc to implement the interception of user requests and the authorization of simulated permissions. Using a third-party security framework will be easier to implement. The next chapter is a quick start of the spring security framework.

Guess you like

Origin blog.csdn.net/qq_44660367/article/details/109515421