SpringSecurity认证

SpringSecurity认证

表单登录流程

  1. 访问资源接口,该接口需要登录才能访问
  2. 请求会走Security中的过滤器链,在FilterSecurityInterceptor被拦截,抛出AccessDeniedException
  3. 该异常会在ExceptionTranslationFilter过滤器被捕获,调研LoginURLAuthenticationEntryPoint的commence方法给客户端返回302,重定向到登录页面
  4. 客户端发生/login请求
  5. /login请求被DefaultLoginPageGeneratingFilter拦截,返回登录页面

原理分析

  1. 自动创建SpringSecurityFilterChain的过滤器,注入到Spring容器中,代理了Spring Security中的过滤器链
  2. 创建UserDetailsService实例,负责提供用户数据,默认是给予内存的
  3. 生成默认登录页面
  4. 开启CSRF防御
  5. 开启其他防御

生成用户

通过UserDetails接口定义用户对象

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

负责提供用户数据源的接口是UserDetailsService#loadUserByUsername

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

实际开发过程中,一般需要自开发UserDetailsService,默认情况下使用的是InMemoryUserDetailsManager管理用户信息。
只需要在application.properties中配置相关信息即可:

spring.security.user.name=user
spring.security.user.password=user
spring.security.user.roles=user,admin

配置

在Security中,如果需要自定义配置,都是继承自WebSecurityConfigurerAdapter来实现的,链式配置。
如:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest()
                .authenticated()
                .and().formLogin().loginPage("/login.htmlm").loginProcessingUrl("/doLogin")
                .defaultSuccessUrl("/index")
                .failureUrl("/fail.html")
                .usernameParameter("name")
                .passwordParameter("passwd")
                .permitAll()
                .and()
                .csrf().disable();
    }
}

defaultSuccessUrl通过重定向实现跳转,客户端跳转
successForwardUrl则是服务器端跳转实现。

Security专门提供了AuthenticationSuccessHandler接口来处理登录事件:

public interface AuthenticationSuccessHandler {
    default void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
        this.onAuthenticationSuccess(request, response, authentication);
        chain.doFilter(request, response);
    }

    void onAuthenticationSuccess(HttpServletRequest var1, HttpServletResponse var2, Authentication var3) throws IOException, ServletException;
}

实现类主要是SimpleUrlAuthenticationSuccessHandler:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.web.authentication;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.security.core.Authentication;

public class SimpleUrlAuthenticationSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler implements AuthenticationSuccessHandler {
    public SimpleUrlAuthenticationSuccessHandler() {
    }

    public SimpleUrlAuthenticationSuccessHandler(String defaultTargetUrl) {
        this.setDefaultTargetUrl(defaultTargetUrl);
    }

    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        this.handle(request, response, authentication);
        this.clearAuthenticationAttributes(request);
    }

    protected final void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION");
        }

    }
}

当需要在前后端分离场景下认证,只需要返回JSON数据即可,那么需要自定义AuthenticationSuccessHandler实现类来返回结果,然后需要在SecurityConfig中加上

.successHandler(new MyAuthenticationSUccessHandler())

那么对应的失败的处理是AuthenticationFailureHandler接口处理,如SimpleUrlAuthenticationFailureHandler。

用户数据获取

从SecurityContextHolder中获取

SecurityContextHolder
包含
SecurityContext
包含
Authentication
包含
Principal、Credentials、Authorities

SecurityContextPersistenceFilter在每次请求到时将HttpSession中获取SecurityContext放入SecurityContextHolder中,在请求结束时再取出并清除信息。

从当前请求对象获取

可以直接将Authentication对象注入到Controller的请求参数中,在此处获取登录用户信息。

用户定义

自定义用户就是使用不同的UserDetailsService的实现类提供用户数据,同时将该自定义类提供给AuthenticationManagerBuilder,系统再将该自定义类提供给AuthenticationProvider使用。

    @Autowired
    private MyUserDetailsServie myUserDetailsServie;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsServie)
    }
上一篇:Appscan10.0.4 -- PowerTools


下一篇:Android中DialogFragment优于Dialog