• SpringBoot2.0.3 + SpringSecurity5.0.6 + vue 前后端分离认证授权


      新项目引入安全控制

      项目中新近添加了Spring Security安全组件,前期没怎么用过,加之新版本少有参考,踩坑四天,终完成初步解决方案.其实很简单,Spring Security5相比之前版本少了许多配置,操作起来更轻量

      MariaDb登录配置加密策略

      SpringSecurity5在执行登录认证时,需预设加密策略.

      坑一:加密策略配置,验密始终不通过,报错401

      坑二:本地重写的UserDetailsService实现类在注入的时候找不到,目前图省事直接用了 @Qualifier制定

      其它,实体类user实现UserDetails,role实现GrantedAuthority与之前版本并有太大变动,可参考很多,不做赘述

      代码如下:  

      /**
         * 项目中重写的 UserDetailsService接口的实现类,需指定
         */
        @Qualifier("userService")
        @Autowired
        private UserDetailsService userDetailsService;
        /**
         * 初始验证登录  从内存中取密码
         * @param auth
         * @throws Exception
         */
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
            auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    
        }

      跨域的问题

      Springboot2.0.3处理跨域的时候特别简单,只需要在

      @EnableWebSecurity
      @Configuration
      @EnableGlobalMethodSecurity(prePostEnabled = true)
      @Order(-1)  
      等修饰下的配置类中的HttpSecurity中,加上 cors()即可,完全不需要写过滤器包装HttpServletResponse的操作  

      登录报错403,权限不足
      这里的解决方案很多,因为本文项目不大,直接关闭 csrf (跨站请求伪造)即可
      同上,csrf().disable()即可.
       
      最大坑--跨域打开,每次登录返回为匿名用户anonymousUser
      问题描述:
        跨域已打开,使用Swagger访问都没有问题,前后端分离时,SpringSecurity也正常工作,最终还是登录不成功,返回匿名用户
        关闭匿名用户即 anonymous().disable(),直接报错401,用户名或密码错误
      遇到这个问题,一直纠结在跨域上,却没有深入去查看前端http请求上给出的信息,原因很简单,登录时重定向的问题
      在HttpSecurity中,在选择 formLogin()时,其后会选择各种成功失败的url,然后代码上去实现相关的接口,其实就入坑了.
      注意:在前端使用ajax登录时,SpringSecurity只能通过重写相关成功/失败/退出等的处理器handler来完成相关处理逻辑
      完整配置类代码:
    @EnableWebSecurity
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    @Order(-1)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        CustomizeAuthenticationSuccessHandler customizeAuthenticationSuccessHandler;
        @Autowired
        CustomizeAuthenticationFailHandler customizeAuthenticationFailHandler;
        @Autowired
        CustomizeAuthenticationAccessDenied customizeAuthenticationAccessDenied;
        @Autowired
        CustomizeAuthenticationLogout customizeAuthenticationLogout;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http
                    .csrf().disable()
                    .anonymous().disable()
                    .cors().and().httpBasic()
                    .and()
                    // 登录成功页面与登录失败页面
                    .formLogin()
                    .successHandler(customizeAuthenticationSuccessHandler).failureHandler(customizeAuthenticationFailHandler).permitAll().and()
                    // 权限不足,即403时跳转页面
                    .exceptionHandling().accessDeniedHandler(customizeAuthenticationAccessDenied).authenticationEntryPoint(new UnauthorizedEntryPoint())
                    .and().logout().logoutSuccessHandler(customizeAuthenticationLogout).permitAll().and()
                    .authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
                    // 无需权限 即可访问
                    .antMatchers("/logout").permitAll()
                    // 需要USER角色才可访问
                    .antMatchers("/person/**").hasRole("PERSON")
                    // 需要ADMIN角色才可访问
                    .antMatchers("/user/**").hasRole("ADMIN");
        }
    
    
        /**
         * 项目中重写的 UserDetailsService接口的实现类,需指定
         */
        @Qualifier("userService")
        @Autowired
        private UserDetailsService userDetailsService;
        /**
         * 初始验证登录  从内存中取密码
         * @param auth
         * @throws Exception
         */
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
            auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    
        }
    
    }

      重写的登录成功处理器代码如下:

    @Component
    public class CustomizeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    
        private static final Logger logger = LoggerFactory.getLogger(CustomizeAuthenticationSuccessHandler.class);
    
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request,
                                            HttpServletResponse response, Authentication authentication)
                throws IOException, ServletException {
    
            logger.info("AT onAuthenticationSuccess(...) function!");
    
            WebAuthenticationDetails details = (WebAuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails();
            logger.info("login--IP:"+details.getRemoteAddress());
    
            SecurityContext context = SecurityContextHolder.getContext();
            Authentication authentication1 = context.getAuthentication();
            Object principal = authentication1.getPrincipal();
            Object principal1 = authentication.getPrincipal();
    
            String name = authentication.getName();
            logger.info("login--name:"+name+" principal:"+principal+" principal1:"+principal1);
    
            PrintWriter out = null;
            try {
                out = response.getWriter();
                out.append(JSONObject.toJSONString(ResponseData.ok().putDataValue("user",principal)
                        .putDataValue("name",name)));
            } catch (IOException e){
                e.printStackTrace();
            }finally {
                if (out != null) {
                    out.close();
                }
            }
        }
    }
  • 相关阅读:
    事件处理之跨浏览器
    IE事件处理
    DOM0级事件处理、DOM2级事件处理
    JS内置对象学习总结
    JS事件响应的学习总结
    vuex的学习例子
    npm run build 打包后,如何运行在本地查看效果(Apache服务)
    Vue.js 引入外部js方法
    Table展开行
    正则表达式test()和exec()、 search() 和 replace()用法实例
  • 原文地址:https://www.cnblogs.com/nyatom/p/9239651.html
Copyright © 2020-2023  润新知