服务器之家

服务器之家 > 正文

java编程SpringSecurity入门原理及应用简介

时间:2022-01-20 12:01     来源/作者:不会编程的派大星

1. SpringSecurity 框架简介

1.1 概要

正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控制),一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两点也是 Spring Security 重要核心功能。

(1) 用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。通俗点说就是系统认为用户是否能登录

(2) 用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。通俗点讲就是系统判断用户是否有权限去做某些事情。

1.2 组成以及同款产品(shiro)对比

1.2.1 Spring Security

SpringSecurity 特点:

  • 和 Spring 无缝整合。
  • 全面的权限控制。
  • 专门为Web 开发而设计。
  • 旧版本不能脱离Web 环境使用。
  • 新版本对整个框架进行了分层抽取,分成了核心模块和Web 模块。单独引入核心模块就可以脱离Web 环境。
  • 重量级。

1.2.2 Shiro

Apache 旗下的轻量级权限控制框架。

特点:

  • 轻量级。Shiro 主张的理念是把复杂的事情变简单。针对对性能有更高要求的互联网应用有更好表现。
  • 通用性。

好处:不局限于Web 环境,可以脱离Web 环境使用。
缺陷:在Web 环境下一些特定的需求需要手动编写代码定制。

Spring Security 是 Spring 家族中的一个安全管理框架,实际上,在 Spring Boot 出现之前,Spring Security 就已经发展了多年了,但是使用的并不多,安全管理这个领域,一直是 Shiro 的天下。

相对于 Shiro,在 SSM 中整合 Spring Security 都是比较麻烦的操作,所以,SpringSecurity 虽然功能比 Shiro 强大,但是使用反而没有 Shiro 多(Shiro 虽然功能没有Spring Security 多,但是对于大部分项目而言,Shiro 也够用了)。

自从有了 Spring Boot 之后,Spring Boot 对于 Spring Security 提供了自动化配置方案,可以使用更少的配置来使用 Spring Security。

因此,一般来说,常见的安全管理技术栈的组合是这样的:

SSM + Shiro
Spring Boot/Spring Cloud + Spring Security

以上只是一个推荐的组合而已,如果单纯从技术上来说,无论怎么组合,都是可以运行的。

1.3 模块划分

java编程SpringSecurity入门原理及应用简介

1.4 SpringSecurity 基本原理

SpringSecurity 本质是一个过滤器链: 从启动是可以获取到过滤器链:

java编程SpringSecurity入门原理及应用简介

代码底层流程:重点看三个过滤器:
FilterSecurityInterceptor:是一个方法级的权限过滤器, 基本位于过滤链的最底部。

1.5.UserDetailsService 接口讲解

当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中
账号和密码都是从数据库中查询出来的。 所以我们要通过自定义逻辑控制认证逻辑。
如果需要自定义逻辑时,只需要实现userDetailsService接口即可,定义如下:

java编程SpringSecurity入门原理及应用简介

 

2.SpringSecurity Web 权限方案

2.1设置登录系统的账号密码(三种方式)

一:在application.xml中自行配置

spring.security.user.name = xxx
spring.security.user.password = xxx

二:编写类实现接口

三:实现数据库认证来完成用户登录
这里就拿一个例子来完成认证和授权

设计数据库表

java编程SpringSecurity入门原理及应用简介

建立springboot项目,勾选相应依赖

java编程SpringSecurity入门原理及应用简介

完整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 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.1.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.example</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>
  </properties>
  <dependencies>
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.9</version>
      </dependency>
      <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.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>2.1.3</version>
      </dependency>
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
      </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>
  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
      </plugins>
  </build>
</project>

数据库配置

spring:
datasource:
  type: com.alibaba.druid.pool.DruidDataSource
  username: root
  password: xxxxxx
  url: jdbc:mysql://xxxxxxxxxx //根据自己情况填写
 

创建对应的实体类

package com.example.demo.domain;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class User implements UserDetails {
  private Integer id;
  private String username;
  private String password;
  private Boolean enabled;
  private Boolean locked;
  private List<Role> roles;
  @Override
  // 实体类和SpringSecurity转换
  public Collection<? extends GrantedAuthority> getAuthorities() {
      List<SimpleGrantedAuthority> authorities = new ArrayList<>();
      for (Role role : roles) {
          authorities.add(new SimpleGrantedAuthority(role.getName()));
      }
      return authorities;
  }
  @Override
  public String getPassword() {
      return null;
  }
  @Override
  public String getUsername() {
      return null;
  }
  @Override
  public boolean isAccountNonExpired() {
      return false;
  }
  @Override
  public boolean isAccountNonLocked() {
      return false;
  }
  @Override
  public boolean isCredentialsNonExpired() {
      return false;
  }
  @Override
  public boolean isEnabled() {
      return false;
  }
  public Integer getId() {
      return id;
  }
  public void setId(Integer id) {
      this.id = id;
  }
  public void setUsername(String username) {
      this.username = username;
  }
  public void setPassword(String password) {
      this.password = password;
  }
  public Boolean getEnabled() {
      return enabled;
  }
  public void setEnabled(Boolean enabled) {
      this.enabled = enabled;
  }
  public Boolean getLocked() {
      return locked;
  }
  public void setLocked(Boolean locked) {
      this.locked = locked;
  }
  public List<Role> getRoles() {
      return roles;
  }
  public void setRoles(List<Role> roles) {
      this.roles = roles;
  }
}

package com.example.demo.domain;
public class Role {
  private Integer id;
  private String name;
  private String nameZh;
  public Integer getId() {
      return id;
  }
  public void setId(Integer id) {
      this.id = id;
  }
  public String getName() {
      return name;
  }
  public void setName(String name) {
      this.name = name;
  }
  public String getNameZh() {
      return nameZh;
  }
  public void setNameZh(String nameZh) {
      this.nameZh = nameZh;
  }
}

创建service层

package com.example.demo.mapper;
import com.example.demo.domain.Role;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.graalvm.compiler.nodeinfo.StructuralInput;
import org.springframework.security.core.userdetails.User;
import java.util.List;
@Mapper
public interface UserMapper {
  @Select("select * from user where username=#{username}")
  public User loadUserByUsername(String username);
  @Select("select * from role r, user_role ur where r.id = ur.rid and ur.uid = #{id}")
  public List<Role> getUserRoleByUid(Integer id);
}

配置spring security

package com.example.demo.config;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configurable
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  private UserService userService;
  @Bean
  PasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
  }
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(userService);
  }
  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
              .antMatchers("/admin/**").hasRole("admin")
              .anyRequest().authenticated()
              .and()
              .formLogin()
              .loginProcessingUrl("/login").permitAll()
              .and()
              .csrf().disable();
  }
}


security配置类说明

java编程SpringSecurity入门原理及应用简介

 

3.security-记住我-的实现

在security配置类中开启remember me功能,并设置有效期。默认时间为两周。

java编程SpringSecurity入门原理及应用简介

 

4.用户注销功能实现

通过退出按钮找到映射地址,在配置类中添加退出映射地址

java编程SpringSecurity入门原理及应用简介

 

5.关于CSRF

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click
attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。

从 Spring Security 4.0 开始,默认情况下会启用CSRF 保护,以防止CSRF 攻击应用程序,Spring Security CSRF 会针对 PATCH,POST,PUT 和DELETE 方法进行防护。

 

6.spring security原理总结

SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链。

现在对这条过滤器链的 15 个过滤器进行说明:

(1) WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。

(2) SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将
SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将
SecurityContextHolder 中的信息清除,例如在 Session 中维护一个用户的安全信息就是这个过滤器处理的。

(3) HeaderWriterFilter:用于将头信息加入响应中。

(4) CsrfFilter:用于处理跨站请求伪造。

(5) LogoutFilter:用于处理退出登录。

(6) UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name 值为 username 和 password,这两个值可以通过设置这个过滤器的 usernameParameter 和 passwordParameter 两个参数的值进行修改。

(7) DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。

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

(9) RequestCacheAwareFilter:用来处理请求的缓存。

(10) SecurityContextHolderAwareRequestFilter:主要是包装请求对象 request。

(11) AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在
Authentication 对象,如果不存在为其提供一个匿名 Authentication。

(12) SessionManagementFilter:管理 session 的过滤器

(13) ExceptionTranslationFilter:处理 AccessDeniedException 和
AuthenticationException 异常。

(14) FilterSecurityInterceptor:可以看做过滤器链的出口。

(15) RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的 remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

以上就是java编程入门SpringSecurity原理及应用简介的详细内容,更多关于java编程SpringSecurity简介的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/weixin_45827693/article/details/114648008?spm=1001.2014.3001.5501

相关文章

热门资讯

蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整
蜘蛛侠3英雄无归3正片免费播放 蜘蛛侠3在线观看免费高清完整 2021-08-24
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
返回顶部