初学springsecurity小案例(基于内存操作)

114 阅读3分钟

简单记录下学习SpringSecurity的过程:

结构:

1.新建springboot项目,导入依赖

<?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>
    <groupId>com.lys</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--        增加数据库支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.lys.DemoApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2.配置文件信息

注意:配置可以登录用户的信息有多种方式:

  • 在application.yml中配置
  • SecurityConfig 继承WebSecurityConfigurerAdapter,重写configure(AuthenticationManagerBuilder auth) 实现
  • 重写UserDetailsService userDetailsService() 方法,通过new JdbcUserDetailsManager()并返回实例用户
spring:
  security:
    user:
      name: lys
      password: 123
      roles: admin
  datasource:
    url: jdbc:mysql://localhost:3306/security?serverTimezone=UTC&characterEncoding=UTF-8
    username: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: root

3.SecurityConfig配置类

方式一:

package com.lys.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import javax.sql.DataSource;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    DataSource dataSource;//自动装配数据库源信息
    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
        manager.setDataSource(dataSource);
        if (!manager.userExists("Tom")) {
            manager.createUser(User.withUsername("Tom").password("123").roles("admin").build());
        }
        if (!manager.userExists("Jack")) {
            manager.createUser(User.withUsername("Jack").password("123").roles("user").build());
        }
        return manager;
    }
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();     //不启用密码加密
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")	//只有admin角色可以访问/admin/**下资源
                .antMatchers("/user/**").hasRole("user") //只有user角色可以访问/user/**下资源
                .anyRequest().authenticated().and()	
                .formLogin().loginPage("/login.html").defaultSuccessUrl("/index.html") //自定义登录验证页面,登录成功后自动跳转主页
                .and()
                .logout()
                .logoutUrl("/logout")	//注销请求
                .logoutSuccessUrl("/login.html") //成功注销后重定向回
                .deleteCookies()	//删除cookies信息
                .clearAuthentication(true) //清除身份验证
                .invalidateHttpSession(true) 
                .permitAll()
                .and()
                .csrf().disable();
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()	//设置不拦截的资源
                .antMatchers("/js/**", "/css/**", "/images/**");
    }
}

方式二:将用户信息写入内存中,这种方式不需要连接数据库

package com.lys.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import javax.sql.DataSource;
/**
 * 简述:
 *
 * @author:LiYansheng
 * @date:2021/08/26 22:43
 * @version:
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        身份验证管理器生成器
        // 在内存中定义用户信息
        auth.inMemoryAuthentication()
                .withUser("li")
                .password("123")
                .roles("user")
                .and()
                .withUser("lys")
                .password(("123"))
                .roles("admin");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated().and()
                .formLogin().loginPage("/login.html").defaultSuccessUrl("/index.html")
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login.html")
                .deleteCookies()
                .clearAuthentication(true)
                .invalidateHttpSession(true)
                .permitAll()
                .and()
                .csrf().disable();
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/js/**", "/css/**", "/images/**");
    }
}

4.写controller

package com.lys.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
        return "hello!!!(任何人都可以访问)";
    }

    @GetMapping("/user/hello")
    public String user() {
        return "hello user(专属)";
    }
    @GetMapping("/admin/hello")
    public String admin() {
        return "hello,admin(专用)";
    }
    @RequestMapping("/index")
    public String toIndexPage() {
        return "/index.html";
   }
}

5.自定义前端页面

登录页:login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div style="width: 30%"></div>
<div style="text-align: center;border: 2px solid #2bb3ff;border-radius: 20%;width: 40%">
    <form action="/login.html" method="post">
        <div class="input">
            <label for="name">账号:</label>
            <input type="text" name="username" id="name">
            <span class="spin"></span>
        </div>
        <div class="input">
            <label for="pass">密码:</label>
            <input type="password" name="password" id="pass">
            <span class="spin"></span>
        </div>
        <div class="button login">
            <button type="submit">
                <span>登录</span>
                <i class="fa fa-check"></i>
            </button>
        </div>
    </form>
</div>
<div style="width: 30%"></div>
</body>
</html>

主页:index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>

<div style="text-align: right">
    <a href="/logout">注销</a>
</div>
<div>
    <h1>我是首页</h1>
    <p>内容balabala</p>
</div>
</body>
</html>

6.登录后跳转的主页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>

<div style="text-align: right">
    <a href="/logout">注销</a>
</div>
<div>
    <h1>我是首页</h1>
    <p>内容balabala</p>
</div>
</body>
</html>

7.启动器

package com.lys;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author 胜胜
 */
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

8.测试

  • 启动项目后访问http://127.0.0.1:8080/hello ,我们会发现并不能直接访问,浏览器会给自动重定向到登录页面

  • 我们先用用户“Tom"登录,其角色为”admin",登录成功后,可以看到以下页面,这个页面是所有用户都可以访问的

  • 访问首页index.html正常

  • 换一个角色是”user"的用户“jack"登录

  • 访问/user/hello,可以看到正常显示

  • “user"角色访问/admin/hello,可以看到是不能正常访问的,/admin/hello只有”admin"角色的用户可以访问

小白初步尝试,有不对的地方欢迎指正!