环境配置: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命名空间配置登陆相关信息的标签,它包含以下属性:
login-page
自定义登陆页url,默认为/login
login-processing-url
登陆请求拦截的url,也就是form表单提交时指定的actiondefault-target-url
默认登陆成功后跳转的urlalways-use-default-target
是否老是使用默认的登陆成功后跳转url
authentication-failure-url
登陆失败后跳转的urlusername-parameter
用户名的请求字段 默认为userName
password-parameter
密码的请求字段 默认为password
authentication-success-handler-ref
指向一个AuthenticationSuccessHandler
用于处理认证成功的请求,不能和default-target-url
还有always-use-default-target
同时使用authentication-success-forward-url
用于authentication-failure-handler-ref
authentication-failure-handler-ref
指向一个AuthenticationFailureHandler
用于处理失败的认证请求authentication-failure-forward-url
用于authentication-failure-handler-ref
authentication-details-source-ref
指向一个AuthenticationDetailsSource
,在认证过滤器中使用login-page
在请求须要登陆认证的api,发现用户没有通过登陆认证,spring security 会自动跳转到配置的login-page
的路由(方法,url,controller...)login-page
直接返回json格式的响应login-page
的controller返回页面login-page
的controller对请求做出判断,选择不一样的返回方式便可先后端分离的状况下,登陆请求,客户端须要的是一个rest的返回结果,而不是跳转url,这就须要咱们去作一些自定义的配置
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)); } }
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 星期六