美文网首页
User must be authenticated with

User must be authenticated with

作者: 无我_无他_有你 | 来源:发表于2022-08-05 18:01 被阅读0次

    错误:User must be authenticated with Spring Security before authorization can be completed.

    简要说下错误原因:
    该错误是oauth2 授权码模式 访问接口 /oauth/authorize 时,由于SpringSecurity上下文中没有用户认证信息,所以在spring security 中拦截报错。源码中 在/oauth/authorize 接口debug可以看到问题。

    处理方法
    错误信息已经说明了是要先认证,所以我们在请求/oauth/authorize接口前认证用户信息即可

    1.1 通过写一个用户身份过滤器进行处理,代码如下

    
    @Component
    @Slf4j
    public class TokenAuthenticationFilter extends OncePerRequestFilter {
    
        @Autowired
        AuthenticationManager authenticationManager;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                        FilterChain filterChain) throws ServletException, IOException {
            String token = request.getHeader(HttpConstant.Header.AUTHENTICATION);
            if (StrUtil.isBlank(token)) {
                //解析请求参数 request.getQueryString()
                Map<String, String> parameters = HttpParamUtil.getRequestParameters(request);
                if (SecurityConstants.AUTH_CODE_URL.equals(request.getRequestURI())&&parameters.size()>0) {
                    //参数中提取 clientId ,根据client 数据库查询用户信息进行身份认证
                    String clientId = parameters.get("client_id");
                    //根据clientId查询用户信息 省略数据库用户信息查询
                    String  username="admin";
                    String password="123456";
                    //账号密码认证
                    JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(username, password);
                    // 通过authenticationManager
                    Authentication authentication = authenticationManager.authenticate(jwtAuthenticationToken);
                    // 认证成功后将认证信息存储到SpringSecurity上下文中
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
                filterChain.doFilter(request, response);
                //在过滤器中添加return,是为了结束该方法的运行,也就是结束过滤
                return;
            }
        }
    }
    

    方法逻辑说明:用户请求中没有认证令牌token,判断请求路径是否是/oauth/authorize,如果是同时判断是否携带有参数(携带参数是请求授权的请求,生成授权码的请求没有参数),如果有则解析参数获取cliend_id,根据cliend_id 查询数据库该用户信息,完成spring security 的鉴权并将认证信息息存储到SpringSecurity上下文中

    1.2 spring security 核心配置类中 注册以上的过滤器,并指定该过滤器为spring security 一系列过滤器的首个过滤器
    1.3 spring security 核心配置类中 对 以 /oauth 开头的请求放行

    
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private UserDetailsService userDetailsService;
        @Autowired
        private MyLogOutSuccessHandler logOutSuccessHandler;
        @Autowired
        private SimpleAccessDeniedHandler simpleAccessDeniedHandler;
        @Autowired
        private SimpleAuthenticationEntryPoint simpleAuthenticationEntryPoint;
        @Autowired
        private TokenAuthenticationFilter tokenAuthenticationFilter;
    
        /**
         * http请求拦截认证
         *
         * @param http
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf
            http.csrf().disable();
            http.authorizeRequests()
                    .and()
                    .formLogin() //新增login form支持用户登录及授权
                    //自定义登录页面
                    .loginPage("http://localhost:3000/login")
                    //认证成功跳转的页面
                    .successForwardUrl("http://localhost:3000/index")
                    .failureForwardUrl("http://localhost:3000/login")
                    .and()
                    .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("http://localhost:3000/login")
                    .logoutSuccessHandler(logOutSuccessHandler)
                    .permitAll()
    
                    //wagger 相关请求放行
                    .and()
                    .authorizeRequests()
                    //oauth相关请求放行
                    .antMatchers("/oauth/**").permitAll()
                    .antMatchers("/login/**").permitAll()
                    .antMatchers("/logout/**").permitAll()
                    .antMatchers("/swagger-ui.html").permitAll()
                    .antMatchers("/swagger-resources").permitAll()
                    .antMatchers("/swagger-ui/*").permitAll()
                    .antMatchers("/v2/api-docs").permitAll()
                    .antMatchers("/v3/api-docs").permitAll()
                    .antMatchers("/webjars/**").permitAll()
    
                    // 其他所有请求需要身份认证
                    .anyRequest().authenticated()
    
                    //配置自定义异常处理
                    .and().exceptionHandling()
                    .accessDeniedHandler(simpleAccessDeniedHandler)
                    .authenticationEntryPoint(simpleAuthenticationEntryPoint);
    
            // 添加自定义  过滤器  ,放置在身份认证过滤器前
            http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        }
    
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) {
            // 使用自定义登录身份认证组件
            auth.authenticationProvider(new JwtAuthenticationProvider(userDetailsService));
        }
    
    
        /**
         * AuthenticationManager对象在OAuth2认证服务中要使用,提前放入IOC容器中
         */
        @Bean
        @Override
        public AuthenticationManager authenticationManager() throws Exception {
            return super.authenticationManager();
        }
    
    }
    

    相关文章

      网友评论

          本文标题:User must be authenticated with

          本文链接:https://www.haomeiwen.com/subject/qgbpwrtx.html