spring security 自定义处理登陆

2020-06-11  本文已影响0人  Sunshine__7b8f

spring security

自定义处理登陆

pom

 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
 <dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.68</version>
 </dependency>

目录结构

配置类

/**
  * @author spp
  * @date 2020-06-11 14:17
  **/
 @EnableWebSecurity
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
  final
  AuthUserDetailsServiceImpl userDetails;
  final
  AuthSuccessHandler authSuccessHandler;
  final
  AuthFailHandler authFailHandler;
 ​
  public SecurityConfig(AuthSuccessHandler authSuccessHandler, AuthFailHandler authFailHandler, AuthUserDetailsServiceImpl userDetails) {
  this.authSuccessHandler = authSuccessHandler;
  this.authFailHandler = authFailHandler;
  this.userDetails = userDetails;
  }
 ​
  @Override
  public void configure(WebSecurity web) throws Exception {
  //忽略请求,不经过security过滤器链
  web.ignoring().mvcMatchers(HttpMethod.GET,"/**");
  }
 ​
  /**
  * 从容器中取出 AuthenticationManagerBuilder,执行方法里面的逻辑之后,放回容器
  * @param authenticationManagerBuilder x
  * @throws Exception
  */
  @Autowired
  public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
  authenticationManagerBuilder.userDetailsService(userDetails).passwordEncoder(new BCryptPasswordEncoder());
  }
 ​
  @Override
  public void configure(HttpSecurity http) throws Exception {
  //解决跨域问题。cors 预检请求放行,让Spring security 放行所有preflight request(cors 预检请求)
  http.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();

  http.authorizeRequests()
  .antMatchers("/admin/**")
  .hasAuthority("root")
  .antMatchers("/").permitAll();
 ​
  //登陆
  http.addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
  //处理异常情况:认证失败和权限不足
  http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
  response.getWriter().println("认证失败");
  }).accessDeniedHandler((request, response, accessDeniedException) -> {
  response.getWriter().println("你的权限不足以访问该资源");
  });
  }
 ​
  /**
  * 登陆拦截器
  * @return
  * @throws Exception
  */
  @Bean
  public UsernamePassAuthFilter myUsernamePasswordAuthenticationFilter() throws Exception {
  UsernamePassAuthFilter filter = new UsernamePassAuthFilter();
  //成功后处理
  filter.setAuthenticationSuccessHandler(authSuccessHandler);
  //失败后处理
  filter.setAuthenticationFailureHandler(authFailHandler);
  filter.setAuthenticationManager(authenticationManagerBean());
  return filter;
  }
 ​
 }

自定义的登陆过滤器,继承UsernamePasswordAuthenticationFilter

 /**
  * @author spp
  * @date 2020-06-11 15:14
  * 自定义登陆
  **/
 ​
 public class UsernamePassAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
 ​
  @Autowired
  UserService service;
  public static final String APPLICATION_JSON = "application/json";
  public static final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8";
  @Override
  public Authentication attemptAuthentication(HttpServletRequest request,
  HttpServletResponse response) throws AuthenticationException {
  String contentType = request.getContentType();
 ​
  if (contentType == null){
  throw new AuthException("内容类型不符");
  }
  if ( APPLICATION_JSON.equals(contentType) || APPLICATION_JSON_UTF8.equals(contentType)) {
  UsernamePasswordAuthenticationToken authRequest;
  User user;
  try (InputStream is = request.getInputStream()) {
  int len;
  byte[] b = new byte[2048];
  StringBuilder sb = new StringBuilder();
  while ((len = is.read(b)) != -1){
  sb.append(new String(b,0,len));
  }
  user = JSON.parseObject(sb.toString(),User.class);
  } catch (IOException e) {
  //将异常放到自定义的异常类中
  throw new AuthException(e.getMessage());
  }catch (JSONException j){
  throw new AuthException("参数映射错误"+j.getMessage());
  }
  try {
  if (user != null) {
  //获得账号、密码
  logger.info(user);
  //登陆逻辑
  if ("admin".equals(user.getUsername()) && "123456".equals(user.getPassword())){
  authRequest = new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword());
  setDetails(request, authRequest);
  return getAuthenticationManager().authenticate(authRequest);
  }else {
  throw new AuthException("用户名密码不匹配");
  }
  }
  } catch (Exception e) {
  throw new AuthException(e.getMessage());
  }
  return null;
  } else {
  response.setStatus(405);
  throw new AuthException("内容类型不符");
  }
  }
 }

自定义登陆成功处理类,实现AuthenticationSuccessHandler接口

/**
  * @author spp
  * @date 2020-06-11 14:28
  **/
 @Slf4j
 @Component
 public class AuthSuccessHandler implements AuthenticationSuccessHandler {
  @Override
  public void onAuthenticationSuccess(HttpServletRequest request,
  HttpServletResponse response,
  Authentication authentication) throws IOException {
  //取得账号信息
  UserDetails userDetails = (UserDetails) authentication.getPrincipal();
  log.info(userDetails + "--->>登陆成功");
  response.getWriter().println("success");
  }
 }

自定义登陆失败处理类,实现AuthenticationFailureHandler接口

/**
  * @author spp
  * @date 2020-06-09 16:50
  **/
 @Component
 @Slf4j
 public class AuthFailHandler implements AuthenticationFailureHandler {
  @Override
  public void onAuthenticationFailure(HttpServletRequest request,
  HttpServletResponse response,
  AuthenticationException e) throws IOException {
  log.info("登陆失败--->>>>");
  //输出
  JSONUtil.WriteJSON(request, response,"登陆失败:"+e.getMessage());
  }
 }

登陆成功后给其添加权限或者身份

实体类需要实现UserDetails接口

/**
 * @author spp
 * @date 2020-06-11 14:24
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AuthUser implements UserDetails {
    private String username;
    private String password;
    private Collection<? extends GrantedAuthority> authorities;
 ​
  //账号是否未过期
  @Override
  public boolean isAccountNonExpired() {
    return true;
  }
 ​
  //是否未锁定
  @Override
  public boolean isAccountNonLocked() {
    return true;
  }
 ​
  //凭据是否未过期
  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }
 ​
  //是否启用
  @Override
  public boolean isEnabled() {
    return true;
  }
 }

添加权限类,需要实现UserDetailsService接口

/**
  * @author spp
  * @date 2020-06-11 14:34
  * 登陆成功后添加权限或者身份
  **/
 @Component
 public class AuthUserDetailsServiceImpl implements UserDetailsService {
 ​
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  return new AuthUser(username,new BCryptPasswordEncoder().encode("123456"),null);
  }
 }

测试


上一篇下一篇

猜你喜欢

热点阅读