Spring Security(三)— 基本认证

Spring Security 基本认证

快速入门

我们只需要引入web和spring security依赖即可,如下:

		<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>

提供一个测试接口,代码如下:

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "Hello Spring Security!";
    }
}

当用户访问/hello接口时,会自动跳转到登录页面,登录成功后,才能访问/hello接口。
在这里插入图片描述

默认的登录用户名是user,密码则是随机生成的UUID字符串,在启动日志中可以看到,如下:
在这里插入图片描述

流程分析

在这里插入图片描述
如上图所示:

  1. 客户端(浏览器)发起请求去访问 /hello 接口,这个接口默认是需要认证之后才能访问的。
  2. 这个请求会走一遍Spring Security中的过滤器链,在最后FilterSecurityIntercepor过滤器中被拦截下来,因为系统发现用户未认证。请求拦截下来之后,接下来会抛出AccessDecniedException异常。
  3. 抛出的AccessDecniedException异常在ExceptionTranslationFilter过滤器通过调用LoginUrlAuthenticationEntryPoin#commence方法给客户端返回302,要求客户端重定向到/login页面。
  4. 客户端发送/login请求
  5. /login请求被DefaultLoginPageGeneratingFilter过滤器拦截下来,并在该过滤器中返回登录页面。所以当用户访问/login接口时会首先看到登录页面。

在整个过程中浏览器发送了两次请求,第一个请求是/hello,服务端收到后,返回302,要求客户端重定向到/login,于是客户端又发送了/login请求。

原理分析

虽然只是引入了一个依赖,但是Spring Boot 背后却默默做了很多事情:

  • 开启Spring Security 自动化配置,开启后,会自动创建一个名为springSecurityFilterChain的过滤器,并注入到bean容器中,这个过滤器负责所有的安全管理,包括用户的认证、授权、重定向到登录页等(springSecurityFilterChain 实际上代理了Spring Security 中的过滤器链)。
  • 创建一个userDetailsService实例,UserDetailsService 负责提供用户数据,默认的用户数据是基于内存的用户,用户名为user,密码为随机的UUID字符串。
  • 给用户生成一个登录页面。
  • 开启CSRF攻击防御。
  • 开启会话固定攻击防御。
  • 集成X-XSS-Protection。
  • 集成X-Frame-Options以防止单击劫持。
默认用户生成

Spring Security中定义了UserDetails接口来规范开发者自定义的对象。
UserDetails接口定义如下:

public interface UserDetails extends Serializable {
	//返回当前账户所具备的权限
	Collection<? extends GrantedAuthority> getAuthorities();
	//返回当前账户的密码
	String getPassword();
	//返回当前账户的用户名
	String getUsername();
	//返回当前账户是否过期
	boolean isAccountNonExpired();
	//返回当前账户是否锁定
	boolean isAccountNonLocked();
	//返回当前账户凭证(如密码)是否过期
	boolean isCredentialsNonExpired();
	//当前账户是否可用
	boolean isEnabled();
}

负责提供用户数据源的接口是UserDetailsService,它只有一个查询用户的方法,如下:

public interface UserDetailsService {
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

loadUserByUsername有一个参数是username,这是用户在认证时传入的用户名,最常见的就是用户在登录表单中输入的用户名(实际开发时还可能存在其他情况,例如使用CAS单点登录时,usernme并非表单输入的用户名,而是CAS Server认证成功之后回调的用户名参数),开发者在这里拿到数据之后,再去数据库中查询用户,最终返回一个UserDetails实例。在实际开发过程中需要我们自定义UserDetailsService的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值