zoukankan      html  css  js  c++  java
  • [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

    • 用户不存在

    • 密码错误

    • 登录成功

  • 相关阅读:
    古文_硕鼠,原文及翻译
    使用php模拟post的几种方法
    alpha版、beta版、rc版的意思
    8007003Windows Update遇到未知错误
    树上10只鸟,开枪打死1只,还剩几只?
    [转]乐死我了,怎么样成为一个全栈程序员(Full Stack Developer),附我想专注的语言
    [转]Visual C++ RunTime的特征——非烫即屯
    斗破苍穹中的几个人物图片
    吐槽一下中国的大学的教材
    百度知道里关于C++的讨论
  • 原文地址:https://www.cnblogs.com/chasemeng/p/13631055.html
Copyright © 2011-2022 走看看