Spring Security简单集成

写在前面

在本人刚工作时,如果需要写用户登录模块,我都是使用 session 来完成的。到后面,学习了JWT,然后每次请求携带token字符串,后端解析token字符串,获取用户的一些登录信息。现在,开始学习spring security!

下面的内容,都是根据黑马程序员网站的免费视频进行学习,衷心感谢黑马程序员,哈哈,不多说自己去看视频 2天快速入门Spring Security OAuth2.0认证授权

使用SpringBoot 集成 Spring Security

Flyway 简单了解可以看之前写的笔记:Spring Boot 集成 Flyway
下面的所有代码保存至GitHub: spring-boot-security

示例

  1. 在我们启动项目后,没有登录时,不管访问系统中的任何资源,我们都跳转到了登录页
    在这里插入图片描述
  2. 当我们登录 zhangsan 时(只有/r/r1 权限)

这里验证了登录失败,跳转登录页,登录成功,跳转到成功页面,然后访问/r/r1 有权限正常访问,/r/r2 没权限,报403错误

在这里插入图片描述
3. 登录lisi账号(拥有的角色只有 /r/r2 权限)

和2 同理

在这里插入图片描述
4. 退出

沿用上面登录过后的步骤。可以看见,在退出后,就访问不了资源了。
在这里插入图片描述

一些基本配置

下面只列出了一部分代码,剩下的需要自己去GitHub上下载。

pom.xml

该项目是使用Maven构建的项目

spring-boot-starter-parent : spring boot 框架
spring-boot-starter-web:spring mvc 框架
spring-boot-starter-security: spring security 权限框架
spring-boot-starter-jdbc: 使用jdbcTemplate,写sql语句
mysql-connector-java:mysql 连接驱动
flyway-core :数据库迁移
lombok:减少代码量

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cfl</groupId>
    <artifactId>spring-security</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-security</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</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-test</artifactId>
        </dependency>

        <!--Spring Security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!--MySQL-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <!--Flyway-->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>
        <!--Lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <!-- 数据库版本管理插件-->
            <plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <version>7.2.1</version>
            </plugin>
        </plugins>
    </build>

</project>

application.yml
server:
  port: 8001
  servlet:
    session:
      timeout: 30m
      cookie:
        http-only: true #如果为true,那么浏览器脚本将无法访问cookie
        secure: false # 如果为true,则cookie将仅通过HTTPS连接发送
spring:
  application:
    name: cfl-spring-security
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/spring-security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    minPoolSize: 3
    maxPoolSize: 10
    maxLifetime: 20000
    borrowConnectionTimeout: 30
    loginTimeout: 30
    mainteanceInterval: 60
    maxIdleTime: 60

  ## flyway数据迁移
  flyway:
    #是否开启
    enabled: true
    locations: classpath:db/migration #迁移脚本的位置,默认db/migration
    baseline-on-migrate: true
    table: flyway_schema_history # 记录历史记录的表名称
    out-of-order: false

注意flyway 配置:
这个文件夹下存放sql脚本,项目启动时,会自动执行在这里插入图片描述

代码

WebSecurityConfig.java

spring security 的配置类

package com.cfl.springsecurity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * 类描述:
 * spring security 的配置
 * EnableGlobalMethodSecurity注解 开启方法资源拦截
 * @ClassName WebSecurityConfig
 * @Author msi
 * @Date 2020/12/29 22:40
 * @Version 1.0
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 定义用户信息服务,这里使用的内存方式保存用户信息。
     * @return
     */
//    @Bean
//    public UserDetailsService userDetailsService () {
//        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//        manager.createUser(User.withUsername("zhangsan").password("123456").authorities("p1").build());
//        manager.createUser(User.withUsername("lisi").password("123456").authorities("p2").build());
//        return manager;
//    }

    /**
     * 定义密码编码器
     * @return
     */
   /* @Bean
    public PasswordEncoder passwordEncoder () {
        return NoOpPasswordEncoder.getInstance();
    }*/

    /**
     *  BCrypt
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder () {
        return new BCryptPasswordEncoder();
    }


    /**
     * 配置安全拦截机制(最重要)
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            //  http.authorizeRequests() 方法有多个子节点,每个macher按照他们的声明顺序执行
            .authorizeRequests()
                // 指定"/r/r1"URL,拥有p1权限能够访问
                .antMatchers("/r/r1").hasAuthority("p1")
                // 指定"/r/r2"URL,拥有p2权限能够访问
                .antMatchers("/r/r2").hasAuthority("p2")
                // 指定了"/r/r3"URL,同时拥有p1和p2权限才能够访问
                .antMatchers("/r/r3").access("hasAuthority('p1') and hasAuthority('p2')")
                // 指定了除了r1、r2、r3之外"/r/**"资源,同时通过身份认证就能够访问,这里使用SpEL(Spring Expression Language)表达式
                .antMatchers("/r/**/").authenticated()
                // 剩余的尚未匹配的资源,不做保护
                .anyRequest().permitAll()
            .and()
                // 允许表单登录
                .formLogin()
                // 登录页面,认证失败自动跳到该地址
                .loginPage("/login-view")
                // 自定义登录提交地址
                .loginProcessingUrl("/login")
                // 自定义登录成功的页面地址(认证成功后跳转该地址)
                .successForwardUrl("/login-success")
                // 我们必须允许所有用户访问我们的登录页(例如为验证的用户),这个 formLogin().permitAll() 方法允许任意用户访问基于表单登录的所有的URL。
                .permitAll()
            .and()
                // 提供系统退出支持
                .logout()
                // 设置触发退出操作的URL (默认是 /logout )
                .logoutUrl("/logout")
                // 退出之后跳转的URL。默认是 /login?logout
                .logoutSuccessUrl("/login-view")
                // 定制的 LogoutSuccessHandler ,用于实现用户退出成功时的处理。如果指定了这个选项那么logoutSuccessUrl() 的设置会被忽略。
//                .logoutSuccessHandler(logoutSuccessHandler)
                // 添加一个 LogoutHandler ,用于实现用户退出时的清理工作.默认 SecurityContextLogoutHandler 会被添加为最后一个 LogoutHandler 。
//                .addLogoutHandler(logoutHandler)
                // GET请求
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
                // 删除cookie
                .deleteCookies("JSESSIONID")
                // 指定是否在退出时让 HttpSession 无效。 默认设置为 true
                .invalidateHttpSession(true)
            .and()
                .sessionManagement()
                .invalidSessionUrl("/login-view?error=INVALID_SESSION")
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
    }


}

MvcConfig.java

配置spring mvc

package com.cfl.springsecurity.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {
	
	@Override
    public void addViewControllers(ViewControllerRegistry registry) {
    	// 配置 “/” 地址,重定向到 “/login-view”
        registry.addViewController("/").setViewName("redirect:/login-view");
    }

}

SpringDataUserDetailService.java
package com.cfl.springsecurity.service;

import com.cfl.springsecurity.dao.UserDao;
import com.cfl.springsecurity.model.UserDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 类描述:
 *
 * @ClassName SpringDataUserDetailService
 * @Description TODO
 * @Author msi
 * @Date 2021/1/2 15:20
 * @Version 1.0
 */
@Service
public class SpringDataUserDetailService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    /**
     * 根据账号查询用户信息
     * @param username  账号
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 使用数据库查询用户信息
        UserDto userDto = userDao.getUserByUsername(username);
        if (userDto == null) {
            // 如果用户查不到,返回null,由 provider 抛异常
            return null;
        }

        // 根据用户的id查询用户的权限
        List<String> permissionsByUserId = userDao.findPermissionsByUserId(userDto.getId());
        // 将 permissionsByUserId 转成数组
        String[] permissionArray = new String[permissionsByUserId.size()];
        permissionsByUserId.toArray(permissionArray);


        System.out.println("username = " + username);

        UserDetails userDetails = User.withUsername(userDto.getUsername())
                .password(userDto.getPassword())
                .authorities(permissionArray)
                .build();

        return userDetails;
    }
}

最后

代码文件太多,直接去Github下载
spring-boot-security

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值