溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用JSON格式數據登錄SpringSecurity

發(fā)布時間:2021-05-21 16:18:41 來源:億速云 閱讀:247 作者:Leah 欄目:編程語言

這期內容當中小編將會給大家?guī)碛嘘P如何使用JSON格式數據登錄SpringSecurity,文章內容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)建Spring Boot工程

首先創(chuàng)建SpringBoot工程,添加SpringSecurity依賴,如下:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

添加Security配置

創(chuàng)建SecurityConfig,完成SpringSecurity的配置,如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Bean
  PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser("zhangsan").password("$2a$10$2O4EwLrrFPEboTfDOtC0F.RpUMk.3q3KvBHRx7XXKUMLBGjOOBs8q").roles("user");
  }

  @Override
  public void configure(WebSecurity web) throws Exception {
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginProcessingUrl("/doLogin")
        .successHandler(new AuthenticationSuccessHandler() {
          @Override
          public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
            RespBean ok = RespBean.ok("登錄成功!",authentication.getPrincipal());
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.write(new ObjectMapper().writeValueAsString(ok));
            out.flush();
            out.close();
          }
        })
        .failureHandler(new AuthenticationFailureHandler() {
          @Override
          public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
            RespBean error = RespBean.error("登錄失敗");
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.write(new ObjectMapper().writeValueAsString(error));
            out.flush();
            out.close();
          }
        })
        .loginPage("/login")
        .permitAll()
        .and()
        .logout()
        .logoutUrl("/logout")
        .logoutSuccessHandler(new LogoutSuccessHandler() {
          @Override
          public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
            RespBean ok = RespBean.ok("注銷成功!");
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.write(new ObjectMapper().writeValueAsString(ok));
            out.flush();
            out.close();
          }
        })
        .permitAll()
        .and()
        .csrf()
        .disable()
        .exceptionHandling()
        .accessDeniedHandler(new AccessDeniedHandler() {
          @Override
          public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException e) throws IOException, ServletException {
            RespBean error = RespBean.error("權限不足,訪問失敗");
            resp.setStatus(403);
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.write(new ObjectMapper().writeValueAsString(error));
            out.flush();
            out.close();
          }
        });

  }
}

這里的配置雖然有點長,但是很基礎,配置含義也比較清晰,首先提供BCryptPasswordEncoder作為PasswordEncoder,可以實現對密碼的自動加密加鹽,非常方便,然后提供了一個名為zhangsan的用戶,密碼是123,角色是user,最后配置登錄邏輯,所有的請求都需要登錄后才能訪問,登錄接口是/doLogin,用戶名的key是username,密碼的key是password,同時配置登錄成功、登錄失敗以及注銷成功、權限不足時都給用戶返回JSON提示,另外,這里雖然配置了登錄頁面為/login,實際上這不是一個頁面,而是一段JSON,在LoginController中提供該接口,如下:

@RestController
@ResponseBody
public class LoginController {
  @GetMapping("/login")
  public RespBean login() {
    return RespBean.error("尚未登錄,請登錄");
  }
  @GetMapping("/hello")
  public String hello() {
    return "hello";
  }
}

這里/login只是一個JSON提示,而不是頁面, /hello則是一個測試接口。

OK,做完上述步驟就可以開始測試了,運行SpringBoot項目,訪問/hello接口,結果如下:

如何使用JSON格式數據登錄SpringSecurity

此時先調用登錄接口進行登錄,如下:

如何使用JSON格式數據登錄SpringSecurity

登錄成功后,再去訪問/hello接口就可以成功訪問了。

使用JSON登錄

上面演示的是一種原始的登錄方案,如果想將用戶名密碼通過JSON的方式進行傳遞,則需要自定義相關過濾器,通過分析源碼我們發(fā)現,默認的用戶名密碼提取在UsernamePasswordAuthenticationFilter過濾器中,部分源碼如下:

public class UsernamePasswordAuthenticationFilter extends
    AbstractAuthenticationProcessingFilter {
  public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
  public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";

  private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
  private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
  private boolean postOnly = true;
  public UsernamePasswordAuthenticationFilter() {
    super(new AntPathRequestMatcher("/login", "POST"));
  }

  public Authentication attemptAuthentication(HttpServletRequest request,
      HttpServletResponse response) throws AuthenticationException {
    if (postOnly && !request.getMethod().equals("POST")) {
      throw new AuthenticationServiceException(
          "Authentication method not supported: " + request.getMethod());
    }

    String username = obtainUsername(request);
    String password = obtainPassword(request);

    if (username == null) {
      username = "";
    }

    if (password == null) {
      password = "";
    }

    username = username.trim();

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
        username, password);

    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);

    return this.getAuthenticationManager().authenticate(authRequest);
  }

  protected String obtainPassword(HttpServletRequest request) {
    return request.getParameter(passwordParameter);
  }

  protected String obtainUsername(HttpServletRequest request) {
    return request.getParameter(usernameParameter);
  }
  //...
  //...
}

從這里可以看到,默認的用戶名/密碼提取就是通過request中的getParameter來提取的,如果想使用JSON傳遞用戶名密碼,只需要將這個過濾器替換掉即可,自定義過濾器如下:

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
  @Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE)
        || request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
      ObjectMapper mapper = new ObjectMapper();
      UsernamePasswordAuthenticationToken authRequest = null;
      try (InputStream is = request.getInputStream()) {
        Map<String,String> authenticationBean = mapper.readValue(is, Map.class);
        authRequest = new UsernamePasswordAuthenticationToken(
            authenticationBean.get("username"), authenticationBean.get("password"));
      } catch (IOException e) {
        e.printStackTrace();
        authRequest = new UsernamePasswordAuthenticationToken(
            "", "");
      } finally {
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
      }
    }
    else {
      return super.attemptAuthentication(request, response);
    }
  }
}

這里只是將用戶名/密碼的獲取方案重新修正下,改為了從JSON中獲取用戶名密碼,然后在SecurityConfig中作出如下修改:

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests().anyRequest().authenticated()
      .and()
      .formLogin()
      .and().csrf().disable();
  http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
  CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
  filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
      resp.setContentType("application/json;charset=utf-8");
      PrintWriter out = resp.getWriter();
      RespBean respBean = RespBean.ok("登錄成功!");
      out.write(new ObjectMapper().writeValueAsString(respBean));
      out.flush();
      out.close();
    }
  });
  filter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
    @Override
    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
      resp.setContentType("application/json;charset=utf-8");
      PrintWriter out = resp.getWriter();
      RespBean respBean = RespBean.error("登錄失敗!");
      out.write(new ObjectMapper().writeValueAsString(respBean));
      out.flush();
      out.close();
    }
  });
  filter.setAuthenticationManager(authenticationManagerBean());
  return filter;
}

將自定義的CustomAuthenticationFilter類加入進來即可,接下來就可以使用JSON進行登錄了,如下:

如何使用JSON格式數據登錄SpringSecurity

上述就是小編為大家分享的如何使用JSON格式數據登錄SpringSecurity了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI