spring security 初识(一)

spring security介绍

1. 认识spring security

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

2. 安全框架的选择

其实大家已经了解过可以通过很多方式来保证我们系统的安全,例如 过滤器、拦截器、还有例如框架里类型的如 Apache shiro 和Spring 官方推荐的Spring Security,由于我们公司选择的是Spring Security,所以今天写些关于Spring Security相关的博客,以便今后好复习。

3. Spring Security原理

核心就是一组过滤器链,为了让我们更清楚的学习Spring Securty,我们有必要研究它主要的一些过滤器。
spring security流程图
这个图也是在网上找的,其实在UsernamePasswordAuthenticationFilter得左边还有一个过滤器叫AbstractAuthenticationProcessingFilter,它是我们Spring Security过滤器的开始。
绿色的过滤器是我们可以定义的,绿色的ExceptionTranslationFilter 过滤器是Spring Security提供给我们处理异常的,橙色的FilterSecurityInterceptor 过滤器最后决定是否允许访问我们的资源。
为了更好的学习Spring Security,我们应该打断点跟踪一下源码。加入我们是根据最常用的用户名密码登陆
如下地方打断点。

org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter # doFilter 

大约193行

org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter # attemptAuthentication

大约68行

org.springframework.security.web.access.ExceptionTranslationFilter # doFilter 

大约130行

org.springframework.security.web.access.intercept.FilterSecurityInterceptor # invoke

大约120行
代码调试总结:
选择一个可访问的接口,发现先来到AbstractAuthenticationProcessingFilter接口,然后走了 org.springframework.security.web.access.ExceptionTranslationFilter#doFilter
为什么会先走这里,因为我们随意访问一个服务,都不满足前面几个认证过滤器的要求
3. 执行后到了org.springframework.security.web.access.intercept.FilterSecurityInterceptor#invoke 中的 InterceptorStatusToken token = super.beforeInvocation(fi); 执行后就报错了
4. 返回到了ExceptionTranslationFilter,并且被捕获到了异常信息 Access is denied (拒绝访问)
5. 处理异常信息之后根据配置返回到了登录页面
6. 登录之后,被拦截到 org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#attemptAuthentication
7. 认证成功之后,又经过了 ExceptionTranslationFilter
8. 接着又到了 FilterSecurityInterceptor 会验证是否有权限访问,如果有的话,InterceptorStatusToken token 会返回值,
9. 下一步放行,由于之前处理的是一个登录请求,所以会有一个重定向,到我们访问的api中
只要不是认证请求的话,前面的认证过滤器是不会走的,反而这两个类的流程都会走一遍 ExceptionTranslationFilter 、FilterSecurityInterceptor ; 看来这两个类是真的固定死的流程架子

4.自定义登陆功能
4.1 自定义获取用户信息逻辑

获取用户信息,Spring Security给我们提供了 org.springframework.security.core.userdetails.UserDetailsService
我们只需要继承该接口,重写 loadUserByUsername方法,我们就可以在该方法里面实现自己想做的事。例如我自已继承了 UserDetailsService并重重写了 loadUserByUsername,从数据库中获取用户信息,最后返回 org.springframework.security.core.userdetails.User 对象。

@Service
@Slf4j
public class UserDetailServiceImpl implements UserDetailsService{

    @Autowired
    private UserMapper userMapper;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        com.huawang.hwbasic.pojo.User  user = userMapper.findByUsername(username);
        System.out.println(user);
        log.info("----------->"+user);
        return new User(username,user.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}
4.2 自定义登录

Spring Security 5.0之前默认是采用Http Basic登录方式,登录接口默认是 /login 并且是POST 请求。当然这些我们都是可以自己定义的。
Spring Security为我们提供了org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter抽象类
我们需要自己继承它并重写 configure(HttpSecurity http) 该configure 一共有三个重载方法,这时注意我们选择的是参数为HttpSecurity 的方法。

@Configuration
public class WebSecurityAdapter extends WebSecurityConfigurerAdapter {

    /**
     * 设置加密方式
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    /**
     * 登陆成功Handler
     */
    @Autowired
    private AuthenticationSuccessHandler successHandler;
    /**
     * 登陆失败Handler
     */
    @Autowired
    private AuthencationFailHalder failHalder;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .formLogin()  //选择采用表单登录方式
                .loginPage("/login.html")  // 自定义login.html为自己的登录页面
                .loginProcessingUrl("/form/login")  // 设置处理的登录请求为 /form/login ,Spring Security默认是 /login    
                .successHandler(successHandler)  // 添加登录成功处理Handle
                .failureHandler(failHalder)      // 添加登录失败处理Handle
                .and()
                .authorizeRequests() 
                .antMatchers("/login.html","/form/login").permitAll()  // /login.html ,/form/login 请求匿名账号允许访问
                .anyRequest() //匹配所有的请求,未登录用户不允许访问
                .authenticated()  
                .and().csrf().disable(); // 关闭csrf,在开发中建议关闭掉


    }
4.3 自定义登录处理逻辑
4.3.1 登录成功处理

自定义登录处理逻辑,Spring Security给我们提供了org.springframework.security.web.authentication.AuthenticationSuccessHandler我们只需要实现它,并定义自己的代码既可以了。

@Component
public class LoginSuccessHalder implements AuthenticationSuccessHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(authentication));
    }
}
4.3.2 自定义登录失败处理逻辑

同理处理登录失败逻辑,Spring Security给我们提供了 org.springframework.security.web.authentication.AuthenticationFailureHandler

@Component
public class AuthencationFailHalder implements AuthenticationFailureHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(exception));
    }
}

虽然这个自定义登录的Demo非常简单,但是在实际的项目中,我们可以拿着它拓展自己想要的安全案例。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值