美文网首页
spring security 自定义处理登陆

spring security 自定义处理登陆

作者: Sunshine__7b8f | 来源:发表于2020-06-11 15:16 被阅读0次

    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);
      }
     }
    

    测试


    相关文章

      网友评论

          本文标题:spring security 自定义处理登陆

          本文链接:https://www.haomeiwen.com/subject/ksubtktx.html