• springsecurity+vue实现登陆认证


    通过查看UsernamePasswordAuthenticationFilter获取用户名和密码的实现方法可以看到,默认只能获取form表单提供的数据无法获得请求体中的数据。所以,要想获得请求体中的数据,需要自定义过滤器。

    这里有两种方式获得用户名和密码

    • 直接重写obtainPasswordobtainUsername
    • 查看attemptAuthentication这个方法我们可以发现,用户名和密码是在这个方法里面获得并且使用的,因此我们可以直接重写这个方法。

    1、编写UserAuthenticationFilter过滤器,继承UsernamePasswordAuthenticationFilter

    @Slf4j
    public class UserAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    
        @Autowired
        private AuthenticationManager authenticationManager;
      
        @Override
        public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
                throws AuthenticationException {
            try {
                Employee employee = new ObjectMapper().readValue(req.getInputStream(), Employee.class);
                return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(employee.getUsername(), employee.getPassword()));
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage());
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、IEmployeeService 接口继承UserDetailsService

    public interface IEmployeeService extends IService<Employee>,UserDetailsService {
    
    }
    
    
    • 1
    • 2
    • 3
    • 4

    EmployeeServiceImpl实现类
    这里只需要实现loadUserByUsername方法,验证用户是否存在、是否被禁用

    @Service
    public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService{
    
        @Autowired
        EmployeeMapper employeeMapper;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
            System.out.println(employeeMapper);
            System.out.println(username);
            QueryWrapper<Employee> wrapper = new QueryWrapper<>();
            wrapper.eq("username",username);
            Employee employee = employeeMapper.selectOne(wrapper);
            UserDetails userDetail = User.withUsername(username).password(employee.getPassword()).roles(username).build();
            return userDetail;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3、编写UserLoginAuthenticationProvider,继承DaoAuthenticationProvider

    通过继承DaoAuthenticationProvider,可以自定义用户密码验证并查看异常信息。

    若不实现该类,抛出的异常信息会都变成Bad credentials

    @Component
    public class UserLoginAuthenticationProvider extends DaoAuthenticationProvider {
    
        @Autowired
        private UserDetailsServiceImpl detailsService;
        @Autowired
        private PasswordEncoder encoder;
    
        /**
         * 找到容器中的detailsService,并执行setUserDetailsService方法,完成赋值
         *
         * 必须要给UserDetailsService赋值,否则会出现UnsatisfiedDependencyException
         */
        @Autowired
        private void setDetailsService() {
            setUserDetailsService(detailsService);
        }
    
        @Override
        protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
            String presentedPassword = authentication.getCredentials().toString();
            if (!encoder.matches(presentedPassword, userDetails.getPassword())) {
                throw new BadCredentialsException(messages.getMessage("badCredentials", "用户密码错误"));
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    4、WebSecurityConfig 配置

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        
        @Autowired
        IEmployeeService employeeService;
    
        //注入AuthenticationManager,可能存在同名bean,
        //配置文件中设置allow-bean-definition-overriding: true
        @Bean
        @Override
        protected AuthenticationManager authenticationManager() throws Exception {
            return super.authenticationManager();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
           //使用DetailsService进行数据校验
            auth.userDetailsService(employeeService).passwordEncoder(passwordEncoder());
    
            //使用自定义的Provider,进行数据校验
    //        auth.authenticationProvider(loginAuthenticationProvider);
        }
    
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
        //重要,将UserAuthenticationFilter添加到容器
        @Bean
        public UserAuthenticationFilter userAuthenticationFilter() throws Exception {
            UserAuthenticationFilter filter = new UserAuthenticationFilter();
            //设置验证成功后的回调
            filter.setAuthenticationSuccessHandler((request,response,authentication)->{
    
                //响应成功状态码必须为200
                response.setStatus(200);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                response.setCharacterEncoding("utf-8");
                //将数据以json的形式返回给前台
                response.getWriter().print(JSON.toJSONString(Result.success(null)));
            });
            //设置验证失败后的回调
            filter.setAuthenticationFailureHandler((request,  response,  exception) ->{
    
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                response.setCharacterEncoding("utf-8");
                //将数据以json的形式返回给前台
                response.getWriter().print(JSON.toJSONString(Result.error("登录失败")));
    
            });
            //设置用户发起登陆请求时的url
            filter.setFilterProcessesUrl("/employee/login");
            filter.setAuthenticationManager(authenticationManager());
            return filter;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()   //屏蔽跨站请求
    
                    .authorizeRequests()
                    .anyRequest().permitAll()
                    .and()
                    .formLogin()
    //                .loginPage("employee/login")
                    .loginProcessingUrl("/employee/login")
                    .successForwardUrl("/success");
    
            http.cors(); // 开启跨域
            //添加自定义的过滤器
            http.addFilterAt(userAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    5、axios.defaults.withCredentials=true//开启携带cookies

    本文参考于:http://t.zoukankan.com/xlwq-p-13411575.html

  • 相关阅读:
    python中pydantic库
    ssm毕设项目学生兼职信息管理系统66n7e(java+VUE+Mybatis+Maven+Mysql+sprnig)
    学信息系统项目管理师第4版系列33_信息化发展
    web前端网页设计期末课程大作业:旅游网页主题网站设计——紫色的旅游开发景点网站静态模板(4页)HTML+CSS+JavaScript
    弘辽科技:新手开店入门技巧有哪些?怎么做?
    Yocto buildhistory介绍
    Python数据类型 ——— 元组
    处理器基础知识
    【cmake】find_package设置查找路径
    Altium Designer学习笔记7
  • 原文地址:https://blog.csdn.net/m0_46267375/article/details/126285550