学习Spring Boot:(二十八)Spring Security 权限认证

前言

本文的源码地址
主要实现 Spring Security 的安全认证,结合 RESTful API 的风格,使用无状态的环境。

主要实现是通过请求的 URL ,通过过滤器来做不同的授权策略操作,为该请求提供某个认证的方法,然后进行认证,授权成功返回授权实例信息,供服务调用。

基于Token的身份验证的过程如下:

  1. 用户通过用户名和密码发送请求。
  2. 程序验证。
  3. 程序返回一个签名的token 给客户端。
  4. 客户端储存token,并且每次用于每次发送请求。
  5. 服务端验证token并返回数据。

每一次请求都需要token,所以每次请求都会去验证用户身份,所以这里必须要使用缓存,

基本使用

加入相关依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
了解基础配置
认证的基本信息
public interface UserDetails extends Serializable {
   

    //返回分配给用户的角色列表
    Collection<? extends GrantedAuthority> getAuthorities();
    
    //返回密码
    String getPassword();

    //返回帐号
    String getUsername();

    // 账户是否未过期
    boolean isAccountNonExpired();

    // 账户是否未锁定
    boolean isAccountNonLocked();

    // 密码是否未过期
    boolean isCredentialsNonExpired();

    // 账户是否激活
    boolean isEnabled();
}
获取基本信息
// 根据用户名查找用户的信息
public interface UserDetailsService {
   
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

我们只要实现这个扩展,就能够自定义方式获取认证的基本信息

WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapter 提供了一种便利的方式去创建 WebSecurityConfigurer的实例,只需要重写 WebSecurityConfigurerAdapter 的方法,即可配置拦截什么URL、设置什么权限等安全控制。

下面是主要会是要到的几个配置:

    /**
     * 主要是对身份认证的设置
     * @param auth
     * @throws Exception
     */  
	@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   
		this.disableLocalConfigureAuthenticationBldr = true;
    }
    /**
     * 复写这个方法来配置 {@link HttpSecurity}. 
     * 通常,子类不能通过调用 super 来调用此方法,因为它可能会覆盖其配置。 默认配置为:
     * 
     */
    protected void configure(HttpSecurity http) throws Exception {
   
        logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");

        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin().and()
            .httpBasic();
    }

	/**
	 * Override this method to configure {@link WebSecurity}. For example, if you wish to
	 * ignore certain requests.
	 * 主要是对某些 web 静态资源的设置
	 */
	public void configure(WebSecurity web) throws Exception {
   
	}

认证流程

阅读源码了解。

Spring Security.jpg

AbstractAuthenticationProcessingFilter.doFilter
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
   

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
		// 判断是否是需要验证方法(是否是登陆的请求),不是的话直接放过
        if (!requiresAuthentication(request, response)) {
   
            chain.doFilter(request, response);
            return;
        }
        // 登陆的请求开始进行验证
        Authentication authResult;
        try {
   
            // 开始认证,attemptAuthentication在 UsernamePasswordAuthenticationFilter 中实现
            authResult = attemptAuthentication(request, response);
            // return null 认证失败
            if (authResult == null) {
   
                return;
            }
		// 篇幅问题,中间很多代码删了
        successfulAuthentication(request, response, chain, authResult);
    }
UsernamePasswordAuthenticationFilter.attemptAuthentication
// 接收并解析用户登陆信息,为已验证的用户返回一个已填充的身份验证令牌,表示成功的身份验证,
// 如果身份验证过程失败,就抛出一个AuthenticationException
public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
   
		if (postOnly && !request.getMethod().equals("POST")) {
   
			throw new AuthenticationServiceException(
					"Authentication method not supported: " + request.getMethod());
		}
        // 方法将 request 中的 username 和 password 生成 UsernamePasswordAuthenticationToken 对象,用于 AuthenticationManager 的验证
		String username = obtainUsername(request);
		String password = obtainPassword(request);
		if (username == null) {
   
			username = "";
		}
		if (password == null) {
   
			password = "";
		}
		username = username.trim();
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}
ProviderManager.authenticate

验证 Authentication 对象(里面包含着验证对象)

  1. 如果有多个 AuthenticationProvider 支持验证传递过来的Authentication 对象,那么由第一个来确定结果,覆盖早期支持AuthenticationProviders 所引发的任何可能的AuthenticationException。 成功验证后,将不会尝试后续的AuthenticationProvider。
  2. 如果最后所有的 AuthenticationProviders 都没有成功验证 Authentication 对象,将抛出 AuthenticationException。

最后它调用的是 Authentication result = provider.authenticate(authentication);

只要我们自定义 AuthenticationProvider 就能完成自定义认证。

动手实现安全框架

使用的依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </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.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值