服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - SpringBoot工程中Spring Security应用实践记录流程分析

SpringBoot工程中Spring Security应用实践记录流程分析

2021-12-29 11:53雨田说码 Java教程

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。这篇文章主要介绍了SpringBoot工程中Spring Security应用实践,需要的朋友可以参考下

 

SpringSecurity 应用

 

简介

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

 

认证授权分析

用户在进行资源访问时,要求系统要对用户进行权限控制,其具体流程如图-1所示:

SpringBoot工程中Spring Security应用实践记录流程分析

 

SpringSecurity 架构设计

鸟瞰SpringSecurity 基本技术架构,例如:

SpringBoot工程中Spring Security应用实践记录流程分析

绿色部分是认证过滤器,需要我们自己配置,可以配置多个认证过滤器。认证过滤器可以使用 Spring Security 提供的认证过滤器,也可以自定义过滤器(例如:短信验证)。认证过滤器要在 configure(HttpSecurity http)方法中配置,没有配置不生效。下面会重点介绍以下三个过滤器:

UsernamePasswordAuthenticationFilter 过滤器:该过滤器会拦截前端提交的 POST 方式的登录表单请求,并进行身份认证。

BasicAuthenticationFilter:检测和处理 http basic 认证。

ExceptionTranslationFilter 过滤器:该过滤器不需要我们配置,对于前端提交的请求会直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。

FilterSecurityInterceptor 过滤器:该过滤器是过滤器链的最后一个过滤器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,并由 ExceptionTranslationFilter 过滤器进行捕获和处理。

 

快速入门实践

 

 创建项目

创建security项目,其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>
    
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.2.RELEASE</version>
    </parent>
    <groupId>com.cy</groupId>
    <artifactId>05-security</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
</project>

 

添加项目依赖

第一步:创建项目,其pom.xml文件核心依赖如下:

<dependencies>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

第二步:启动服务(依赖添加以后会默认添加一个tomcat,端口8080)
服务启动之后,你会发现,控制台会出现一个随机的密码,用于访问当前系统,默认用户名是user,密码就是控制台上的密码,如图所示:

SpringBoot工程中Spring Security应用实践记录流程分析

 

启动服务访问测试

服务启动后,打开浏览器进行访问,如图所示:

SpringBoot工程中Spring Security应用实践记录流程分析

输入账号(默认用户名为user)和密码登陆成功默认为如下页面.

SpringBoot工程中Spring Security应用实践记录流程分析

其中,出现这个页面表示还没有配置登陆成功页面,这个资源页面现在还不存在,可以在项目的resources目录下创建static目录(假如没有此目录),然后在此目录下创建index.html页面,内容如下:

<!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title> 
  </head>
  <body>
     <div>
       <h1>The Index Page</h1>
     </div> 
   </body> 
 </html>

此时,再次启动服务进行登陆,呈现登陆成功的效果,如图所示:

SpringBoot工程中Spring Security应用实践记录流程分析

 

自定义认证逻辑

 

认证流程分析

SpringBoot工程中Spring Security应用实践记录流程分析

 

定义security配置类

定义配置类,基于此类配置认证和授权逻辑,例如:

package com.cy.security.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.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 认证授权管理器对用户输入的密码与数据库中存储的密码进行比对时,
     * 需要对这个密码加密,加密算法需要我们自己指定
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);
        //关闭跨域攻击
        http.csrf().disable();
        //自定义登陆表单
        http.formLogin().loginPage("/login.html").loginProcessingUrl("/login");
        //请求资源的认证配置
        http.authorizeRequests()
                .antMatchers("/login","/login.html")
                .permitAll()
                .anyRequest().authenticated();
    }
}

 

定义数据访问层对象

定义数据访问层对象,基于此对象实现用户及用户权限信息的获取,例如:

package com.cy.security.dao;
import com.cy.security.domain.SysUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;

@Mapper
public interface UserMapper {
     /**
     * 基于用户名获取用户信息
     * @param username
     * @return
     */
    @Select("select id,username,password,status " +
            "from tb_users " +
            "where username=#{username}")
     SysUser selectUserByUsername(String username);

    /**
     * 基于用户id查询用户权限
     * @param userId 用户id
     * @return 用户的权限
     * 涉及到的表:tb_user_roles,tb_role_menus,tb_menus
     */
    @Select("select distinct m.permission " +
            "from tb_user_roles ur join tb_role_menus rm on ur.role_id=rm.role_id" +
            "     join tb_menus m on rm.menu_id=m.id " +
            "where ur.user_id=#{userId} and m.permission is not null")
    List<String> selectUserPermissions(Long userId);
}

 

定义UserDetailService接口实现类

Spring Security 提供了一个UserDetailService接口,我们可以基于此接口实现类,实现用户信息的获取和封装,例如:

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;
    /**
     * 客户端点击登陆时,添加些用户信息会传给此方法
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.基于用户名查询用户信息
        SysUser user=userMapper.selectUserByUsername(username);
        //...判断自己写...
        System.out.println(user);
        //2.查询用户登陆用户权限
        List<String> permissions=userMapper.selectUserPermissions(user.getId());
        System.out.println(permissions);
        //3.封装用户信息并返回,将用户信息交给认证管理器,认证授权管理器负责对用户输入的信息进行认证和授权
        List<GrantedAuthority> authorityList =
                AuthorityUtils.createAuthorityList(permissions.toArray(new String[]{}));
        return new User(username, user.getPassword(),authorityList);
    }
}

 

自定义登陆页面

在resources的static目录下创建login.html页面,例如:

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="external nofollow"  rel="stylesheet" 
          integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <title>login</title>
</head>
<body>
<div class="container"id="app">
    <h3>Please Login</h3>
    <form>
        <div class="mb-3">
            <label for="usernameId" class="form-label">Username</label>
            <input type="text" v-model="username" class="form-control" id="usernameId" aria-describedby="emailHelp">
        </div>
        <div class="mb-3">
            <label for="passwordId" class="form-label">Password</label>
            <input type="password" v-model="password" class="form-control" id="passwordId">
        </div>
        <button type="button" @click="doLogin()" class="btn btn-primary">Submit</button>
    </form>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<script>
    var vm=new Vue({
        el:"#app",//定义监控点,vue底层会基于此监控点在内存中构建dom树
        data:{ //此对象中定义页面上要操作的数据
            username:"",
            password:""
        },
        methods: {//此位置定义所有业务事件处理函数
            doLogin() {
                //1.定义url
                let url = "http://localhost:8080/login"
                //2.定义参数
                let params = new URLSearchParams()
                params.append("username",this.username);
                params.append("password",this.password);
                debugger
                //3.发送异步请求
                axios.post(url, params).then((response) => {
                        alert("login ok");
                        location.href="/index.html" rel="external nofollow" 
                })
            }
        }
    });
</script>
</body>
</html>

 

启动服务进行访问测试

SpringBoot工程中Spring Security应用实践记录流程分析

 

授权逻辑设计及实现

 

修改授权配置类

在权限配置类上添加启用全局方法访问控制注解,例如

package com.cy.auth.config;

//这个配置类是配置Spring-Security的,
//prePostEnabled= true表示启动权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SpringSecurityConfigurer extends WebSecurityConfigurerAdapter {

    ……
}

 

定义资源访问对象

package com.cy.res.controller;

@RequestMapping("/res")
@RestController
public class ResourceController {
    @PreAuthorize("hasAuthority("sys:res:view")")
    @RequestMapping("/retrieve")
    public String doRetrieve(){
        return "select resource ok";
    }
    @PreAuthorize("hasAuthority("sys:res:create")")
    @RequestMapping("/create")
    public String doCreate(){
        return "create resource";
    }
}

其中,@PreAuthorize注解描述方法时,用于告诉系统访问此方法时需要进行权限检测。需要具备指定权限才可以访问。例如:

 

启动服务实现访问测试

打开浏览器分别输入http://localhost:8080/res/create和http://localhost:8080/res/select进行测试分析。

 

总结(Summary)

本章节主要是对spring security 在springboot平台下是如何使用的。

到此这篇关于SpringBoot工程中Spring Security应用实践的文章就介绍到这了,更多相关Spring Security应用实践内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/maitian_2008/article/details/120191729

延伸 · 阅读

精彩推荐
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7482021-02-04
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30