如何使用JSON格式數(shù)據(jù)登錄SpringSecurity

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

成都創(chuàng)新互聯(lián)公司于2013年開始,先為營口等服務(wù)建站,營口等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為營口企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

創(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("權(quán)限不足,訪問失敗");
            resp.setStatus(403);
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.write(new ObjectMapper().writeValueAsString(error));
            out.flush();
            out.close();
          }
        });

  }
}

這里的配置雖然有點長,但是很基礎(chǔ),配置含義也比較清晰,首先提供BCryptPasswordEncoder作為PasswordEncoder,可以實現(xiàn)對密碼的自動加密加鹽,非常方便,然后提供了一個名為zhangsan的用戶,密碼是123,角色是user,最后配置登錄邏輯,所有的請求都需要登錄后才能訪問,登錄接口是/doLogin,用戶名的key是username,密碼的key是password,同時配置登錄成功、登錄失敗以及注銷成功、權(quán)限不足時都給用戶返回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接口,結(jié)果如下:

如何使用JSON格式數(shù)據(jù)登錄SpringSecurity

此時先調(diào)用登錄接口進(jìn)行登錄,如下:

如何使用JSON格式數(shù)據(jù)登錄SpringSecurity

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

使用JSON登錄

上面演示的是一種原始的登錄方案,如果想將用戶名密碼通過JSON的方式進(jìn)行傳遞,則需要自定義相關(guān)過濾器,通過分析源碼我們發(fā)現(xiàn),默認(rèn)的用戶名密碼提取在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);
  }
  //...
  //...
}

從這里可以看到,默認(rèn)的用戶名/密碼提取就是通過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類加入進(jìn)來即可,接下來就可以使用JSON進(jìn)行登錄了,如下:

如何使用JSON格式數(shù)據(jù)登錄SpringSecurity

上述就是小編為大家分享的如何使用JSON格式數(shù)據(jù)登錄SpringSecurity了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

新聞名稱:如何使用JSON格式數(shù)據(jù)登錄SpringSecurity
網(wǎng)站路徑:http://bm7419.com/article48/goeiep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、微信小程序商城網(wǎng)站、服務(wù)器托管搜索引擎優(yōu)化、企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司