[Spring Security] 前后端分離項目中后端登錄代碼的簡單示例


一.前言

  • 環境:springboot 2.3.0、springsecurity 5.3.2
  • 這篇隨筆可能對其他人很不友好,因為只貼了相關的代碼,所以不建議大家參考,我只是寫給自己看的,但是跟大家分享一下;
  • 如果代碼有問題的話請告訴我,但是其他的如代碼不規范什么的就不必了,我知道我很渣,存在很多問題;
  • 管理員這個實體類只有 idusernamepassword 這三個屬性
  • 該代碼沒有權限控制,沒有會話管理等其他的功能,只有登錄驗證功能,所以較為簡單
  • 下面每個各種處理器都必須在第6點中的 MySecurityConfiguration 中注冊,否則無法生效
  • 代碼已經驗證過,沒問題

二.代碼

導包(略……)

1.自定義登錄邏輯(訪問數據庫)

/**
 * @author Chase Meng
 * @description: 自定義登錄邏輯(訪問數據庫)
 * @created on 2020/9/7
 */
@Configuration
public class CustomizeUserDetailsService implements UserDetailsService {
    @Autowired
    private LoginOperate loginOperate;
    @Autowired
    private PasswordEncoder passwordEncoder;
//    @Autowired
//    private Encryption encryption;

//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException  {
        Admin admin =loginOperate.findUserByUsername(username);
        if(username==null||username.equals("")){
            throw new RuntimeException("用戶名不能為空!");
        }
        if(admin==null){
            throw new RuntimeException("用戶名不存在!");
        }
        List<GrantedAuthority> authorities=new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_"+"normal"));  //由於沒有設置授權,所以隨便給一個身份normal
        User userDetails = new User(admin.getUsername(), passwordEncoder.encode(admin.getPassword()), authorities);
        return userDetails;
    }
}

2.自定義登錄失敗處理器

**
 * @author Chase Meng
 * @description: 自定義登錄失敗處理器
 * @created on 2020/9/7
 */
@Component
public class CustomizeAuthenctiationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        //super.onAuthenticationFailure(request, response, exception);
        Result result=new Result();
        if(exception instanceof BadCredentialsException){
            //密碼錯誤
            result.setCode(1200);
            result.setMsg("密碼錯誤!");
        }else if(exception instanceof InternalAuthenticationServiceException){
            //用戶不存在
            result.setCode(1100);
            result.setMsg("不存在該用戶!");
        }
        else if(exception instanceof AccountExpiredException){
            //賬號過期
        }
        else if(exception instanceof CredentialsExpiredException){
            //密碼過期
        }else if(exception instanceof DisabledException){
            //帳號不可用
        }else if(exception instanceof LockedException){
            //帳號鎖定
        }else{
            //其他錯誤
        }
        result.setState(false);
        // 把result對象轉成 json 格式 字符串 通過 response 以application/json;charset=UTF-8 格式寫到響應里面去
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(result.toJsonWhenDataIsNull());
    }
}
/**
 * 或者使用實現AuthenticationFailureHandler類的方法來定義
 */
//@Component
//public class CustomizeAuthenctiationFailureHandler implements AuthenticationFailureHandler {
//    @Override
//    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//        ......//    }
//}

3.自定義登錄成功處理器

/**
 * @author Chase Meng
 * @description: 自定義登錄成功處理器
 * @created on 2020/9/7
 */
@Component
public class CustomizeAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        Result result = new Result();
        result.setCode(2000);
        result.setMsg("登錄成功!");
        result.setState(true);
        Admin admin=new Admin();
        result.setData("{\"username\" : \""+SecurityContextHolder.getContext().getAuthentication().getName()+"\"}");//響應數據攜帶用戶名
        // 把result對象轉成 json 格式 字符串 通過 response 以application/json;charset=UTF-8 格式寫到響應里面去
        httpServletResponse.setContentType("application/json; charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        out.write(result.toJsonWhenDataIsNull());
    }
}
/**
 * 或者使用實現AuthenticationSuccessHandler類的方法來定義
 */
/*@Component
public class CustomizeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        ......
    }
}*/

4.屏蔽重定向的登錄頁面,並返回統一的json格式的數據

/**
 * @author Chase Meng
 * @description: 屏蔽重定向的登錄頁面,並返回統一的json格式的數據
 * @created on 2020/9/7
 */
@Component
public class CustomizeAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        Result result=new Result();
        httpServletResponse.setContentType("application/json; charset=utf-8");
        result.setCode(1000);
        result.setMsg("沒有登錄權限,請先登錄!");
        result.setState(false);
        PrintWriter out = httpServletResponse.getWriter();
        out.write(result.toJsonWhenDataIsNull());
    }
}

5.自定義注銷成功處理器

/**
 * @author Chase Meng
 * @description: 自定義注銷成功處理器
 * @created on 2020/9/7
 */
@Component
public class CustomizeLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        Result result=new Result();
        httpServletResponse.setContentType("application/json; charset=utf-8");
        result.setCode(1000);
        result.setMsg("注銷成功!");
        result.setState(true);
        PrintWriter out = httpServletResponse.getWriter();
        out.write(result.toJsonWhenDataIsNull());
        httpServletResponse.getWriter().flush();
    }
}

6.自定義spring security配置

/**
 * @author Chase Meng
 * @Description 自定義spring security配置
 * @Date Create in 2020/09/07
 */

@EnableWebSecurity
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomizeAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired
    private CustomizeAuthenctiationFailureHandler myAuthenctiationFailureHandler;
    @Autowired
    private CustomizeAuthenticationEntryPoint myAuthenticationEntryPoint;
    @Autowired
    private CustomizeLogoutSuccessHandler logoutSuccessHandler;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置攔截規則
        //按先后注冊的先后順序匹配,因此順序要格外注意
        http.authorizeRequests()
                .antMatchers("/upload/picture").permitAll() //放行圖片上傳接口
                .antMatchers("/*d/**").authenticated()  //攔截所有對回收站的查詢
                .antMatchers(HttpMethod.GET).permitAll()    //放行其他所有GET請求
                .anyRequest().authenticated()   //攔截其余請求
                .and()
                .csrf().disable();  // 禁用跨站攻擊,否則允許通行的其他路徑的除了get請求之外的都會被攔截(包括登錄注銷接口)
        //開啟跨域
        http.cors();
        //開啟自動配置登錄
        http.formLogin().permitAll()
                .successHandler(myAuthenticationSuccessHandler) //注冊自定義處理器
                .failureHandler(myAuthenctiationFailureHandler)
//                .loginPage("http://localhost:8080/")    //登錄頁(GET)
                .loginProcessingUrl("/user/login");    //登錄接口(POST)

        //記住密碼
//        http.rememberMe();

        //屏蔽Spring Security默認重定向登錄頁面以實現前后端分離功能
        http.exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint);//匿名用戶訪問無權限資源時的異常
//                .accessDeniedHandler();   //用來解決認證過的用戶訪問無權限資源時的異常
        http.logout().permitAll()
                .logoutSuccessHandler(logoutSuccessHandler)  //注冊登錄失敗處理器
                .deleteCookies("JSESSIONID")    //登出后刪除cookie
                .logoutUrl("/user/logout"); //登出接口(POST)
    }
}

 三.結果

數據庫中只有一個管理員:

username:admin

password:abc123

  • 用戶不存在

  • 密碼錯誤

  • 登錄成功

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM