一、序言

1、SpringSecurity简介

它是一款基于Spring项目的安全认证框架,利用了spring ioc,依赖注入和面向切面编程等思想,可以做到身份认证和授权管理等安全机制。
很多时候我们使用系统的某些功能,不同的角色登录,可能看到的导航功能不一样,但单单的从ui层面去控制功能的展示使用时候完全不够的,因为稍微会些web编程的,就会拿到界面按钮和导航条对应的请求路径,通过直接或者模拟传参的方式,也是可以调用后天的接口,拿到数据。真正的安全应该是从请求资源上进行控制,也就是说,对于不同的用户角色,对于后台资源的使用权限是不一样的,具体到程序上就是通过后台处理方法级别的安全认证,这些对于Security时候完全能够达到的。

2、SpringSecurityh 和 Apache Shiro 的区别和选择

这两个都是用于访问权限进行认证的框架,Shiro他的特点是强大且灵活,能够非常清晰的处理身份验证、授权、管理会话以及密码加密等工作。SpringSecurity是spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,他是在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。它的核心功能:身份认证,访问授权,安全防护(防跨站请求等)等
两者的区别:

Shiro

SpringSecurity

入手简单;依赖低适用于各种项目;功能简单易于理解

上手复杂;依赖于spring框架的项目;功能比 Shiro 更加丰富些

总结:两个都是大组织的开源项目,社区活跃度比较高,两者在安全功能上都较为可靠和稳定,在选择上如果是小型项目,可以入手Shiro,周期较短;如果是大型项目,或者是Spring、微服务相关的,建议直接入手 ,spring一系列的产品,功能的融化较方便。
【该篇博客主要是通过 Springboot+SpringSecurity+MyBatisPlus 实现前后端分离的后端权限认证框架】

二、SpringSecurity 核心知识

1. Springsecurity 关键类和方法

1.1 接口类:UserDetailsService
方法:… loadUserByUsername(String var1) … 实现登录逻辑的具体地方,返回的对象为 UserDetails

1.2 接口类:UserDetails
方法:…getAuthorities()… 获取对应的权限;
方法:…isAccountNonExpired()… 判断账户是否未过期;
方法:…isAccountNonLocked()… 判断账户是否未被锁定;
方法:…isCredentialsNonExpired()… 判断凭证(密码)是否未过期;
方法:…isEnabled()…账户是否启用状态;

1.3 实现类:User---- implements UserDetails
注意:这里的User要和我们实际项目中的数据库实体对象UserEntity区分开;
里面有两个构造方法:
》public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {} 该构造方法调用了下面7个参数的构造方法
》public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {}

1.4 接口类: PasswordEncoder
登录用户密码的加解密功能:
方法:…encode(CharSequence var1)… 加密方法;
方法:…matches(CharSequence var1, String var2)…匹配,第一个是前端传来的明文密码,第二是加密好的密码;
方法:…upgradeEncoding(String encodedPassword)… 对已经加密的密码再次进行加密;
有很多的加解密算法实现类:{BCryptPasswordEncoder-官方推荐的,SCryptPasswordEncoder等等}

1.5 接口类:Authentication
认证功能接口:
方法:…getAuthorities()… 获取权限方法;
方法:…getCredentials()… 获取凭证方法(密码);
方法:…getDetails()… 获取详情的方法;
方法:…getPrincipal()… 获取User;
方法:…isAuthenticated()… 是否是被认证的;

1.6 CSRF知识:
跨域,通过伪造用户请求访问受信任站点的非法请求访问;
springsecurity在4之后,默认是开启了 csrf防护。开启之后,在首次登陆时,会返回 _csrf 值,后面所有的请求都要带上 _csrf 参数值。如果不使用,在 WebSecurityConfigurerAdapter的子类上要加上 http.csrf().disable()

1.7 基于注解的访问控制

Security除了常用的,在configure方法中通过配置的方式设置访问的权限控制,还可以通过注解的形式,但是默认是没有开启的,要在在继承WebSecurityConfigurerAdapter的类上加注解: @EnableGlobalMethodSecurity 进行开启:

spring官方认证_spring官方认证


下面是常用权限认证注解:

@EnableGlobalMethodSecurity(jsr250Enabled=true)

开启@RolesAllowed 注解过滤权限

  • JSR-250注解
    @DenyAll 拒绝所有访问
    @RolesAllowed({“USER”, “ADMIN”}) 该方法只要具有"USER", "ADMIN"任意一种权限就可以访问。这里可以省 略前缀ROLE_,实际的权限可能是ROLE_ADMIN

@EnableGlobalMethodSecurity(prePostEnabled=true)
使用表达式时间方法级别的安全性 4个注解可用

  • prePostEnabled注解
    @preAuthorize注解:表示访问方法或类在执行之前先判断权限,大多数情况下都是使用这个注解,参数是权限表达式;
    @postAuthorize注解:表示方法或者类执行结束之后判断权限,很少被使用的注解;

@EnableGlobalMethodSecurity(securedEnabled=true)
开启@Secured 注解过滤权限

  • securedEnabled 注解
    @Secured() 判断是否有角色的

1.8 WebSecurityConfigurerAdapter 类:适配器

方法:protected void configure(HttpSecurity http) throws Exception{}

作用:用来配置Security的授权策略,也就是http请求策略,什么请求要什么样的权限许可,是链式编程,

spring官方认证_spring_02

方法:public void configure(AuthenticationManagerBuilder auth) throws Exception { }

作用:用来配置认证信息的,AuthenticationManagerBuilder 主要有两种认证策略:

①.基于内存的用户认证:

spring官方认证_User_03


②.基于jdbc的用户认证:

spring官方认证_spring官方认证_04

2. Oauth2 认证

第三方认证技术,主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要遵循一定的接口协议。

OAUTH协议为用户资源的授权提供了一个安全的、开放的、简易的标准。任何第三方都可以用OAUTH认证服务,他是开放的,目前发展到了2.0,被广泛的使用。实现 认证 和 资源 服务的分类。

spring官方认证_用户认证_05

Oauth 授权认证的模式,目前有四种方式:
①授权码模式:最复杂的最安全的用的最多的一个模式,第三方应用先申请一个授权码,然后再用该码获取令牌;

②隐藏式:RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit);
③密码式:如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)
④凭证式:适用于没有前端的命令行应用,即在命令行下请求令牌。
详细可参考博客.

3. JWT 标准

他是一种开放的 WEB 行业标准,定义了一种协议格式,分为三段:头部、荷载和签名。

eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIwMTkwMTMiLCJleHAiOjE2MTM3NTgxNjUsImNyZWF0ZWQiOjE2MTM3MTQ5NjUwMzYsImF1dGhvcml0aWVzIjpbeyJhdXRob3JpdHkiOiJTWVM6Uk9MRV9TVVBfQURNSU46REVMRVRFIn1dfQ.Yar_GOyXadHJJj-sqpwmuhXoL9SZZKaRAh3q3HGX7qDOFWayjbziDgwJ8UfCEjc4ogqErki8q8qZ5zD3crwuYA

头部:关于该 JWT 的最基本的信息,如类型以及签名所用的算法。
荷载(负载):存放有效信息的地方,如过期时间。该部分是通过base64编码,不要存放重要信息。
签名:存的是签证信息(头部编码后的字符串+荷载编码后的字符串+盐 再进行base64 的编码形成)注意这里的盐保存在服务端的,是保密的,这部分也是他安全性的保证。

JWT 令牌的优点:

  • 基于 json,方便解析;
  • 可以在令牌中自定义丰富的内容,易扩展;
  • 安全性较高;
  • 资源服务使用 JWT 可以不依赖认证服务就完成授权(这点要和我们通过Oauth 授权认证模式进行区分)。