SpringSercurity基本原理

spring sercurity 基础


环境配置:html

win10java

idea 2019.1git

jdk1.8spring

spring cloud Finchley.RELEASE数据库

spring-boot 2.0.2.RELEASEjson

git && gitee.com后端


基本原理

一系列的过滤器组成的链路.以下图:api


FilterSercurityInterceptor就是spring security处理鉴权的入口,在访问REST api 前都会通过这个过滤器,若是经过了鉴权才会跳转到对应api的入口app

下面来分析在默认开启spring security的状况下各类场景的一些执行路径,经过流程图展现出来;前后端分离

对应操做: 打断点在FilterSecurityInterceptor.doFilter()上,便可追踪其执行路径

未登陆,请求REST api

已登陆,请求REST api,权限不够

已登陆,请求REST api,权限足够


自定义用户认证逻辑

自定义认证配置信息:

须要继承WebSecurityConfigurerAdapter,并重写其configure()方法.

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 说明: 重写security的配置方法
     * @author suwenguang
     * @date 2019/6/7
     * @return void <- 返回类型
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置
        http.formLogin()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated();
    }
}

处理用户信息获取逻辑

实现UserDetailsService接口

@Component
@Slf4j
public class UserCertificationService implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("用户名:{}", username);
        log.info("密码:{}",passwordEncoder.encode("123456"));
        //根据username到数据库获取用户信息
        return new User(username, passwordEncoder.encode("123456")
                ,true,true,true,true,
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin,user"));
    }
}

处理用户校验逻辑

利用UserDetails

UserDetails是个接口,能够实现等方式建立本身系统的子类,以达到扩展的效果.固然也可使用自带的. org.springframework.security.core.userdetails.User

UserDetails内部提供以下的四种状态

  • 帐号是否已过时 isAccountNonExpired
  • 帐号是否锁定 isAccountNonLocked
  • 密码是否已过时 isCredentialsNonExpired
  • 帐号是否启用 isCredentialsNonExpired


处理密码加密解密

PasswordEncoder

配置一个PasswordEncoder

新建PasswordEncoderConfig.java

@Configuration
public class PasswordEncoderConfig {
    /**
     * 说明: 注入一个明文密码的加解密
     * @author suwenguang
     * @date 2019/6/7
     * @return org.springframework.security.crypto.password.PasswordEncoder <- 返回类型
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

个性化用户认证

form-login属性详解

form-login是spring security命名空间配置登陆相关信息的标签,它包含以下属性:

  1. login-page 自定义登陆页url,默认为/login
  2. login-processing-url 登陆请求拦截的url,也就是form表单提交时指定的action
  3. default-target-url 默认登陆成功后跳转的url
  4. always-use-default-target 是否老是使用默认的登陆成功后跳转url
  5. authentication-failure-url 登陆失败后跳转的url
  6. username-parameter 用户名的请求字段 默认为userName
  7. password-parameter 密码的请求字段 默认为password
  8. authentication-success-handler-ref 指向一个AuthenticationSuccessHandler用于处理认证成功的请求,不能和default-target-url还有always-use-default-target同时使用
  9. authentication-success-forward-url 用于authentication-failure-handler-ref
  10. authentication-failure-handler-ref 指向一个AuthenticationFailureHandler用于处理失败的认证请求
  11. authentication-failure-forward-url 用于authentication-failure-handler-ref
  12. authentication-details-source-ref 指向一个AuthenticationDetailsSource,在认证过滤器中使用

自定义登陆界面

  1. 设置 上述属性login-page 在请求须要登陆认证的api,发现用户没有通过登陆认证,spring security 会自动跳转到配置的login-page的路由(方法,url,controller...)
  2. 若是是rest api 服务(先后端分离),不须要返回html页面,能够在指定的 login-page 直接返回json格式的响应
  3. 若是是须要返回html页面,也能够在 login-page 的controller返回页面
  4. login-page 的controller对请求做出判断,选择不一样的返回方式便可

自定义登陆成功处理

先后端分离的状况下,登陆请求,客户端须要的是一个rest的返回结果,而不是跳转url,这就须要咱们去作一些自定义的配置

  1. 建立一个类实现AuthenticationSuccessHandler接口,实现onAuthenticationSuccess()方法,把Authentication信息包装成json返回.

新建SystemAuthenticationSuccessHandler.java

@Component
@Slf4j
public class SystemAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    /**
     * 说明:登陆成功后,执行的方法
     * @author suwenguang
     * @date 2019/6/8
     * @return void <- 返回类型
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登陆成功:{}", JSON.toJSONString(authentication));
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        Response res = ResponseBuilder.build(ResponseEnums.SIMPLE_SUCCESS, authentication);
        writer.write(JSON.toJSONString(res));
    }
}
  1. 在spring security config类里面配置上successHandler(),把刚刚的类做为参数传入便可

修改SecurityConfig.java

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private SystemAuthenticationSuccessHandler systemAuthenticationSuccessHandler;
    /**
     * 说明: 重写security的配置方法
     * @author suwenguang
     * @date 2019/6/7
     * @return void <- 返回类型
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置
        http.formLogin()
                //自定义登陆方法
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                //自定义登陆认证成功处理器
                .successHandler(systemAuthenticationSuccessHandler)
                .and()
                .authorizeRequests()
                //配置不须要认证的路由
                .antMatchers("/login.html","**static**").permitAll()
                //全部路由都要认证
                .anyRequest().authenticated()
                //禁用跨站攻击防御机制
                .and().csrf().disable()
                ;
    }
}

自定义登陆失败处理

道理同上,可是此次须要实现的接口变成了AuthenticationFailureHandler,其余步骤几乎同上

下面贴上处理的代码

新建SystemAuthenticationFailHandler.java

@Component
@Slf4j
public class SystemAuthenticationFailHandler implements AuthenticationFailureHandler {
    /**
     * 说明: 认证失败后,执行的方法
     * @author suwenguang
     * @date 2019/6/8
     * @return void <- 返回类型
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("登陆失败:{}", exception.getMessage());
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        Response res = ResponseBuilder.build(ResponseEnums.LOGIN_FAIL, exception.getMessage());
        writer.write(JSON.toJSONString(res));
    }
}

修改SecurityConfig.java

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    /**
     * 登陆成功的处理器
     **/
    @Autowired
    private SystemAuthenticationSuccessHandler systemAuthenticationSuccessHandler;

    /**
     * 登陆失败的处理器
     **/
    @Autowired
    private SystemAuthenticationFailHandler systemAuthenticationFailHandler;
    /**
     * 说明: 重写security的配置方法
     * @author suwenguang
     * @date 2019/6/7
     * @return void <- 返回类型
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置
        http.formLogin()
                //自定义登陆方法
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                //自定义登陆认证成功处理器
                .successHandler(systemAuthenticationSuccessHandler)
				//自定义登陆失败处理器
                .failureHandler(systemAuthenticationFailHandler)
                .and()
                .authorizeRequests()
                //配置不须要认证的路由
                .antMatchers("/login.html","**static**").permitAll()
                //全部路由都要认证
                .anyRequest().authenticated()
                //禁用跨站攻击防御机制
                .and().csrf().disable()
                ;
    }
}

2019-06-08 20:54:47 星期六

相关文章
相关标签/搜索