自定义认证过滤器和自定义授权过滤器

news2024/9/28 2:47:57

目录

通过数据库动态加载用户信息

具体实现步骤

一.创建数据库

二.编写secutity配置类

三.编写controller

四.编写服务类实现UserDetailsService接口类

五.debug springboot启动类

认证过滤器

 SpringSecurity内置认证流程

 自定义认证流程

 第一步:自定义一个类继承AbstractAuthenticationProcessingFilter类

 第二步:把自定义的认证过滤器交给spring管理,并配置认证的路径

第三步:把自定义的认证过滤器配置在默认认证过滤器之前

 第四步:测试

 基于JWT实现无状态认证 

第一步:编写生成jwt票据工具类

 第二步:在认证成功后执行的方法里生成jwt令牌并返回给前端

第三步:结果

SpringSecurity基于Jwt实现认证小结 

授权过滤器

 授权流程

自定义授权过滤器流程

第一步:自定义一个类继承 OncePerRequestFilter类

 第二步:把这个授权过滤器交给spring管理

 第三步:测试


通过数据库动态加载用户信息

使用SpringSecurity时,访问某一个资源路径时,SpringSecurity会自动拦截,并跳转到登录页面(SpringSecurity提供),登录之后才可以访问指定的资源。

登录的这个过程就是用户的认证

认证的具体过程就是:Spring Security底层会自动调用UserDetailsService类型bean提供的用户信息前端返回的用户信息进行合法比对,如果比对成功则资源放行,否则就认证失败;

所以我们需要创建一个UserDetailsService对象bean给spring容器管理

具体的步骤就是需要创建一个类实现UserDetailsService接口,重写loadUserByUsername()方法,

UserDetails loadUserByUsername(String userName)

用户认证时自动调用这个方法,userName就是前端输入的明文密码

调用这个方法的目的就是加载一个用户类,让SpringSecurity底层拿去与前端返回的用户信息进行比对

在这个方法里面根据用户名去数据库查找这个用户的信息(用户名,用户密文密码,用户拥有的权限集合),然后封装到User类(实现了UserDetails接口)对象里,最后返回即可。

 返回的这个用户信息就会被SpringSecurity底层自动调用去与前端返回的用户信息进行合法比对

 总的来说就是:用户的认证是先调用loadUserByUsername方法,根据前端返回的用户名根据数据库查找这个用户的详细信息(用户名,用户密码密文,用户的权限集合),然后封装成一个UserDetails类,然后Spring Security底层再自动调用UserDetailsService类型bean提供的用户信息前端返回的用户信息进行合法比对,如果比对成功则资源放行,否则就认证失败;

用户类中的是用户的密文密码,而前端返回的用户密码是密文,SpringSecurity要怎么比对呢

所以我们要配置BCryptPasswordEncoder加密相关bean,底层会自动调用这个bean把密码密文与密码明文进行匹配,所以我们存入数据库的密码密文需要使用BCrypt算法加密

具体实现步骤

一.创建数据库

create database security_demo default charset=utf8mb4;
use security_demo;

CREATE TABLE `tb_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  `roles` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `tb_user` VALUES (1, 'hhh', '$2a$10$f43iK9zKD9unmgLao1jqI.VluZ.Rr/XijizVEA73HeOu9xswaUBXC', 'ROLE_ADMIN,P5');
INSERT INTO `tb_user` VALUES (2, 'aaa', '$2a$10$f43iK9zKD9unmgLao1jqI.VluZ.Rr/XijizVEA73HeOu9xswaUBXC', 'ROLE_SELLER,P7,ROLE_ADMIN');

密码都是123456经过BCrypt算法加密后的

二.编写secutity配置类

@Configuration
@EnableWebSecurity//开启web安全设置生效
//开启SpringSecurity相关注解支持
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //TODO:返回一个BCryptPasswordEncoder密码加密类类,让SpringSecurity自动调用把密码密文和明文进行匹配
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()//开启默认form表单登录方式
                .and()
                .logout()//登出用默认的路径登出 /logout
                .permitAll()//允许所有的用户访问登录或者登出的路径
                .and()
                .csrf().disable()//启用CSRF,防止CSRF攻击
                .authorizeRequests();//授权方法,该方法后有若干子方法进行不同的授权规则处理

               /* //允许所有账户都可访问(不登录即可访问),同时可指定多个路径
                .antMatchers("/register").permitAll()//允许所有的用户访问
                .antMatchers("/hello").hasAuthority("P1") //具有P5权限才可以访问
                .antMatchers("/say").hasRole("SELECT") //具有ROLE_ADMIN 角色才可以访问,会自动加上ROLE_
                .antMatchers("/aa","/bb").hasAnyAuthority("P1","ROLE_SELECT")//有任意一个权限都可以访问
                .antMatchers("/aa","/bb").hasAnyRole("SELECT")//有任意一个权限都可以访问
                .antMatchers("/aa","/bb").hasIpAddress("192.168.xxx.xxx")//必须是192.168.地址才能访问
                .antMatchers("/aa","/bb").denyAll()//任何用户都不可以访问
                .anyRequest().authenticated(); //除了上边配置的请求资源,其它资源都必须授权才能访问*/
    }
}

三.编写controller

使用注解给每个资源接口授权,拥有指定权限才能进行访问

@RestController
public class UserController {
    //拥有ROLE_ADMIN权限的用户才能访问此接口
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/hello")
    public String hello(){
        return "hello security";
    }

    //拥有ROLE_SELECT权限的用户才能访问此接口
    @PreAuthorize("hasRole('SELECT')")
    @GetMapping("/say")
    public String say(){
        return "say security";
    }

    @PermitAll//任何用户都可以访问此接口,不需要进行认证
    @GetMapping("/register")
    public String register(){
        return "register security";
    }
}

四.编写服务类实现UserDetailsService接口类

注意:

1.User是UserDetails接口的实现类,封装了用户权限相关的的数据及用户的权限数据, 不要导错包 ;

2.工程已经配置好了BCryptPasswordEncoder加密相关bean,底层会自动调用;

/**
 * 创建一个UserDetailsService类bean,用户认证时自动调用loadUserByUsername方法加载用户信息
 * 之后SpringSecurity会使用这个用户类与前端返回的用户信息进行合法比对,成功才能放行资源
 */
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private TbUserMapper tbUserMapper;
    /**
     * 通过用户名去数据库获取这个用户的具体信息(用户名,用户密文密码,用户的权限集合)创建一个用户类
     * @param userName 前端返回的用户名字
     * @return 返回一个用户类
     * @throws UsernameNotFoundException 用户不存在的异常
     */
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //根据用户名去数据库查找用户的基本信息(用户名,密文密码,用户的权限集合)
        TbUser tbUser = tbUserMapper.findByUserName(userName);
        if(tbUser==null){
            throw new UsernameNotFoundException("该用户不存在");
        }
        //封装UserDetails类,User是UserDetails接口的实现类
        //使用工具类把用户的权限使用逗号进行分割
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(tbUser.getRoles());
        UserDetails user = User.builder()
                .username(tbUser.getUsername())
                .password(tbUser.getPassword())
                .authorities(authorities)
                .build();
        //返回这个用户类,之后SpringSecurity会使用这个用户类与前端的返回的用户信息进行比对
        //自动调用BCryptPasswordEncoder bean把用户明文密码与用户密文密码进行比对
        return user;
    }
}

五.debug springboot启动类

访问hello接口(拥有ROLE_ADMIN权限才能访问),会自动跳到springsecurity提供的用户认证界面

会跳转到loadUserByUsername方法,并获取前端的用户名,然后使用这个用户名创建一个用户类

 认证通过,即springSecurity会自动调用BCryptPasswordEncoder加密相关bean把密文密码和明文密码继续比对,比对通过就是认证通过,又因为hhh用户拥有ROLE_ADMIN权限,所以可以访问

认证过滤器

 SpringSecurity内置认证流程

核心流程梳理如下:

  • 认证过滤器(UsernamePasswordAuthentionFilter)接收form表单提交的账户、密码信息,并封装成UsernamePasswordAuthenticationToken认证凭对象;
  • 认证过滤器调用认证管理器AuthenticationManager进行认证处理;
  • 认证管理器通过调用用户详情服务获取用户详情UserDetails;
  • 认证管理器通过密码匹配器PasswordEncoder进行匹配,如果密码一致,则将用户相关的权限信息一并封装到Authentication认证对象中;
  • 认证过滤器将Authentication认证过滤器放到认证上下文,方便请求从上下文获取认证信息;

 自定义认证流程

SpringSecurity内置的认证过滤器是基于post请求且为form表单的方式获取认证数据的,那如何接收前端Json异步提交的数据据实现认证操作呢?

​ 显然,我们可仿照UsernamePasswordAuthentionFilter类自定义一个过滤器并实现认证过滤逻辑;

 第一步:自定义一个类继承AbstractAuthenticationProcessingFilter类

在这个类中我们要重写 attemptAuthentication()方法,在这个方法中把前端收到的用户名,用户明文密码封装成 UsernamePasswordAuthenticationToken票据对象中,然后调用认证管理器认证这个用户的信息(就是使用UserDetailsService返回的用户类的密文密码通过密码匹配与用户明文密码进行比对)

我们还有重写一个构造器,在这个构造器中确定认证登录的地址

/**
 * 自定义过滤器,继承AbstractAuthenticationProcessingFilter类
 */
public class MyUserNamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private static final String USER_NAME="username";
    private static final String PASSWORD="password";
    /**
     * 自定义构造器,传入认证登录的url地址
     * @param loginUrl 登录的url地址
     */
    public MyUserNamePasswordAuthenticationFilter(String loginUrl) {
        super(loginUrl);
    }

    /**
     * 尝试去认证的方法,把前端返回的用户名和密码封装到UsernamePasswordAuthenticationToken认证凭对象;
     * data:{"username":"hhh","password":"123456"}
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        //判断请求方法必须是post提交,且提交的数据的内容必须是application/json格式的数据
        if (!request.getMethod().equalsIgnoreCase("POST") || !MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(request.getContentType()))
        {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //获取前端传入的json数据,并解析成map集合
        //获取请求参数
        //获取reqeust请求对象的发送过来的数据流
        ServletInputStream in = request.getInputStream();
        //将数据流中的数据反序列化成Map
        HashMap<String,String> loginInfo = new ObjectMapper().readValue(in, HashMap.class);
        String username = loginInfo.get(USER_NAME);
        username = (username != null) ? username : "";
        username = username.trim();
        String password = loginInfo.get(PASSWORD);
        password = (password != null) ? password : "";

        //将用户名和密码信息封装到认证票据对象下
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        //调用认证管理器认证指定的票据对象
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    /**
     * 认证成功后执行的方法
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
       //获取封装后的用户对象
//这一个principal对象里的密码为null
        User principal=(User)authResult.getPrincipal();
        String username = principal.getUsername();
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        //设置返回数据格式
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        //设置返回数据编码格式
        response.setCharacterEncoding("UTF-8");
        Map<String,String> info=new HashMap<>();
        info.put("msg","认证成功");
        info.put("code","1");
        info.put("data","");
        //把类对象变成json数据
        String jsonData = new ObjectMapper().writeValueAsString(info);
        //将json数据返回
        response.getWriter().write(jsonData);
    }

    /**
     * 认证失败执行的方法
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        //设置响应数据为json
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        //设置响应数据格式
        response.setCharacterEncoding("UTF-8");
        //设置响应的数据
        Map<String,String>info=new HashMap<>();
        info.put("msg","认证失败");
        info.put("code","0");
        info.put("data","");
        //将数据封装成json数据
        String jsonData = new ObjectMapper().writeValueAsString(info);
        response.getWriter().write(jsonData);
    }
}

 第二步:把自定义的认证过滤器交给spring管理,并配置认证的路径

在这个自定义的认证过滤器bean中,需要注入一个认证管理器的bean

 /**
     * 自定义认证过滤器
     *  隐含:如果认证成功,则在安全上下文中维护认证相关信息
     *      如果安全上下文中存在认证相关信息,则默认的UserNamePasswordAuthenticationFilter认证过滤器就不会执行
     *      所以执行顺序,自定义的过滤器在前,默认的过滤器在后
     * @return
     * @throws Exception
     */
    @Bean
    public MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter() throws Exception {
        //构造认证过滤器对象,并设置认证路径 /myLogin
        MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter = new MyUserNamePasswordAuthenticationFilter("/myLogin");
        //注入一个认证管理器bean
        myUserNamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
        return myUserNamePasswordAuthenticationFilter;
    }

第三步:把自定义的认证过滤器配置在默认认证过滤器之前

因为只要自定义的认证过滤器认证成功,就会在安全上下文中维护认证成功的相关信息,这样就不会去执行默认的认证过滤器

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()//开启默认form表单登录方式
                .and()
                .logout()//登出用默认的路径登出 /logout
                .permitAll()//允许所有的用户访问登录或者登出的路径
                .and()
                .csrf().disable()//启用CSRF,防止CSRF攻击
                .authorizeRequests();//授权方法,该方法后有若干子方法进行不同的授权规则处理

        //对于自定义过滤器,需要创建一个实例,所以用方法返回一个自定义认证过滤器
        http.addFilterBefore(myUserNamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

               /* //允许所有账户都可访问(不登录即可访问),同时可指定多个路径
                .antMatchers("/register").permitAll()//允许所有的用户访问
                .antMatchers("/hello").hasAuthority("P1") //具有P5权限才可以访问
                .antMatchers("/say").hasRole("SELECT") //具有ROLE_ADMIN 角色才可以访问,会自动加上ROLE_
                .antMatchers("/aa","/bb").hasAnyAuthority("P1","ROLE_SELECT")//有任意一个权限都可以访问
                .antMatchers("/aa","/bb").hasAnyRole("SELECT")//有任意一个权限都可以访问
                .antMatchers("/aa","/bb").hasIpAddress("192.168.xxx.xxx")//必须是192.168.地址才能访问
                .antMatchers("/aa","/bb").denyAll()//任何用户都不可以访问
                .anyRequest().authenticated(); //除了上边配置的请求资源,其它资源都必须授权才能访问*/
    }

 第四步:测试

访问myLogin接口

 基于JWT实现无状态认证 

​ JWT是无状态的,所以在服务器端无需存储和维护认证信息,这样会大大减轻服务器的压力,所以我们可在自定义的认证过滤器认证成功后通过successfulAuthentication方法向前端颁发token认证字符串;

第一步:编写生成jwt票据工具类

public class JwtTokenUtil {
    // Token请求头
    public static final String TOKEN_HEADER = "authorization";
    // Token前缀
    public static final String TOKEN_PREFIX = "Bearer ";

    // 签名主题
    public static final String SUBJECT = "JRZS";
    // 过期时间,单位毫秒
    public static final long EXPIRITION = 1000 * 60 * 60* 24 * 7;
    // 应用密钥
    public static final String APPSECRET_KEY = "hhha";
    // 角色权限声明
    private static final String ROLE_CLAIMS = "role";

    /**
     * 生成Token
     */
    public static String createToken(String username,String role) {
        Map<String,Object> map = new HashMap<>();
        map.put(ROLE_CLAIMS, role);

        String token = Jwts
                .builder()a
                .setSubject(username)
                .setClaims(map)
                .claim("username",username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRITION))
                .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
        return token;
    }

    /**
     * 校验Token
     */
    public static Claims checkJWT(String token) {
        try {
            final Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
            return claims;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 从Token中获取用户名
     */
    public static String getUsername(String token){
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        return claims.get("username").toString();
    }

    /**
     * 从Token中获取用户角色
     */
    public static String getUserRole(String token){
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        return claims.get("role").toString();
    }

    /**
     * 校验Token是否过期
     */
    public static boolean isExpiration(String token){
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        return claims.getExpiration().before(new Date());
    }
}

 第二步:在认证成功后执行的方法里生成jwt令牌并返回给前端

/**
     * 认证成功后执行的方法
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
       //获取封装后的用户对象
        //这一个principal对象里的密码为null
        User principal=(User)authResult.getPrincipal();
        String username = principal.getUsername();
        Collection<GrantedAuthority> authorities = principal.getAuthorities();

        //使用工具类生成jwt令牌,authorities.toString()把权限集合变成["P1","ROLE_ADMIN]类型
        //构建JwtToken 加入权限信息是为了将来访问时,jwt解析获取当前用户对应的权限,做授权的过滤
        String token = JwtTokenUtil.createToken(username, authorities.toString());

        //设置返回数据格式
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        //设置返回数据编码格式
        response.setCharacterEncoding("UTF-8");
        Map<String,String> info=new HashMap<>();
        info.put("msg","认证成功");
        info.put("code","1");
        info.put("data",token);
        //把类对象变成json数据
        String jsonData = new ObjectMapper().writeValueAsString(info);
        //将json数据返回
        response.getWriter().write(jsonData);
    }

第三步:结果

SpringSecurity基于Jwt实现认证小结 

授权过滤器

 授权流程

自定义授权过滤器流程

第一步:自定义一个类继承 OncePerRequestFilter类

重写doFilterInternal方法,在这个方法中,获取请求头的token票据,并进行校验判断

/**
 * 定义授权过滤器,本质就是获取一切请求头的token信息,进行校验
 */
public class AuthenticationFilter extends OncePerRequestFilter {
    /**
     * 过滤中执行的方法
     * @param request
     * @param response
     * @param filterChain 过滤器链
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //1.从请求头中获取token字符串
        String tokenStr = request.getHeader(JwtTokenUtil.TOKEN_HEADER);

        //2.合法性判断
        //2.1 判断票据信息是否为空
        if(StringUtils.isBlank(tokenStr)){
            //如果票据为空,则放行,但是此时安全上下文中没有认证成功的票据,后续的过滤器如果得不到票据,后面的认证过滤器会进行拦截
            filterChain.doFilter(request,response);
            return;
        }
        //2.2检查票据是否合法,解析失败
        Claims claims = JwtTokenUtil.checkJWT(tokenStr);
        if(claims==null){
            //票据不合法,直接让过滤器终止
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            Map<String,String> info=new HashMap<>();
            info.put("msg","票据无效,请重新认证");
            info.put("data","");
            info.put("code","0");
            //把数据序列化成json格式
            String jsonData = new ObjectMapper().writeValueAsString(info);
            response.getWriter().write(jsonData);
            return;
        }
        //2.3
        //获取用户名
        String username = JwtTokenUtil.getUsername(tokenStr);
        //获取用户权限集合 "["P1","ROLE_ADMIN"]"
        String roles = JwtTokenUtil.getUserRole(tokenStr);
        //解析用户权限字符串
        String stripStr = StringUtils.strip(roles, "[]");
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(stripStr);

        //3.组装数据到UsernamePasswordAuthenticationToken票据对象中
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,null,authorities);

        //4.将封装的认证票据存入security安全上下文中,这样后续的过滤器就可以直接从安全上下文中获取用户的相关权限信息
        //TODO:以线程为维度:当前访问结束,那么线程回收,安全上下文中的票据也会回收,下次访问时需要重新解析
        SecurityContextHolder.getContext().setAuthentication(token);

        //5.放行请求,后续的过滤器,比如:认证过滤器如果发现安全上下文中存在token票据对象,就不会进行重新认证
        filterChain.doFilter(request,response);

    }
}

 第二步:把这个授权过滤器交给spring管理

让这个授权过滤器的优先级高于自定义的认证过滤器,因为如果之前已经认证过,请求头中就会存在token票据,授权过滤器就会解析token票据,并把用户名和用户权限封装到UsernamePasswordAuthenticationToken类对象中,然后把这个对象存入安全上下文中,这样一来后续的认证过滤器就不会重新认证,直接放行

 /**
     * 维护一个授权过滤器bean,检查jwt票据是否有效,并做相关处理
     */
    @Bean
    public AuthenticationFilter authenticationFilter(){
        return new AuthenticationFilter();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()//开启默认form表单登录方式
                .and()
                .logout()//登出用默认的路径登出 /logout
                .permitAll()//允许所有的用户访问登录或者登出的路径
                .and()
                .csrf().disable()//启用CSRF,防止CSRF攻击
                .authorizeRequests();//授权方法,该方法后有若干子方法进行不同的授权规则处理

        //对于自定义过滤器,需要创建一个实例,所以用方法返回一个自定义认证过滤器
        http.addFilterBefore(myUserNamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        //配置授权过滤器,它是资源安全的屏障,优先级最高,所以需要在自定义的认证过滤器之前
        http.addFilterBefore(authenticationFilter(), MyUserNamePasswordAuthenticationFilter.class);
}

 第三步:测试

先通过/myLogin路径进行用户认证获取token票据

一开始会被授权过滤器拦截,但是请求头中票据为空,授权过滤器就会放行,进入到认证过滤器(因为访问路径是/myLogin),然后获取票据信息

 使用该票据访问其他资源,访问成功

授权过滤器解析请求头的票据,把解析到的用户名,用户权限信息存入UsernamePasswordAuthenticationToken类对象,然后再将对象存入安全上下文中,这样后面的过滤器就知道这个用户有哪些权限

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2172023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AFSim仿真系统 --- 系统简解_01(任务模块)

任务 任务是AFSIM的基线可执行文件。通过任务&#xff0c;用户可以访问世界仿真框架&#xff08;WSF&#xff09;。该可执行文件&#xff08;mission.exe&#xff09;解释文本格式的仿真输入文件&#xff08;场景&#xff09;&#xff0c;以生成仿真&#xff0c;并可选择以多种…

c语言中的杨氏矩阵的介绍以及元素查找的方法

杨氏矩阵&#xff1a;是一个二维数组 特点&#xff1a;数组的每行从左到右都是递增的 数组的每列从上到下都是递增的 这种矩阵结构使得在查找特定元素时&#xff0c;可以利用其 递增性质来缩小范围&#xff0c;提高查找效率。 从杨氏矩阵中对元素进行查找 1&#xff0c;要求…

沟通技巧对班组长的工作效率有什么影响?

在企业管理的细微脉络中&#xff0c;班组长作为基层管理的中坚力量&#xff0c;其工作效率直接影响着整个生产线的流畅度与团队士气。而沟通技巧&#xff0c;作为人际交往的桥梁&#xff0c;不仅在日常交流中扮演着重要角色&#xff0c;更在班组管理中发挥着不可替代的作用。本…

Bigemap Pro首发(一款真正全面替代Arcgis的国产基础软件)

Bigemap Pro是一款功能强大的计算机数据要素辅助设计(Computer-Aided Data Elements Design CADED)软件&#xff0c;由成都比格图数据处理有限公司研发设计&#xff0c;主要应用在数据要素设计领域&#xff0c;为各行业提供安全可靠高效易用的数据要素设计类国产化基础软件。Bi…

2024年汉字小达人区级自由报名倒数4天:最新问题和今年比赛方式和题型解析

今天是2024年第十一届汉字小达人的区级自由报名活动的第三天&#xff0c;也是倒数第四天。 今天是星期五&#xff0c;通常孩子们放学会早一点。接下来是周六有一整天的时间可用&#xff0c;周日、周一又要上课了&#xff0c;所以实际上可用的较多的备考时间就是今天晚上和明天…

华为OD机试 - 西天取经 - 广度优先搜索BFS(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

windows上设置某exe开机自启动。亲测有效

亲测有效方法 1。通过文件夹启动 0。先创建exe的快捷方式 1。 winR 2。输入shell::startup 3.将exe的快捷方式复制或拖动到打开的文件夹 通过启动文件夹 创建您的EXE文件的快捷方式。 打开文件资源管理器&#xff0c;导航到 C:\Users\YourUsername\AppData\Roaming\Microsoft\…

CORE MVC 过滤器 (筛选器)

MVC FrameWork MVCFramework MVC Core 过滤器 分 同步、异步 1、 授权筛选器 IAuthorizationFilter&#xff0c;IAsyncAuthorizationFilter 管道中运行的第一类筛选器&#xff0c;用来确定发出请求的用户是否有权限发出当前请求 2、资源筛选器 IResourceFilter &#xff0c;…

操作系统 概论

1. 操作系统★ 1.1. 定义 操作系统(Operating System,简称OS)是一种计算机系统软件(计算机软件可以分为系统软件、支撑软件和应用软件三类),他管理和控制计算机硬件和软件资源,并合理地组织调度计算机工作和资源分配,以提供给用户和其他软件方便的接口和环境。 1.2. …

OpenAI研究员、思维树作者姚顺雨专访:人生是一场无限流游戏丨独家

「人生所有重大的选择&#xff0c;无论买房、选择工作&#xff0c;去做任何事情&#xff0c;都像一个文字游戏。从哲学的角度来看&#xff0c;人生就是一个无限流游戏&#xff0c;每天你都有很多选择&#xff0c;从某种程度上说是非常high level、 open-ended的。」 谈及过往研…

前端基础面试题·第四篇——Vue(其一)

1.v-if 和 v-show的区别 在Vue中这两个命令都用于控制元素的显示与隐藏。 (1) v-if 动态控制元素显示与隐藏&#xff0c;本质上是动态销毁或者重建元素&#xff0c;会触发浏览器重排与重绘。在切换状态时有一个局部编译/卸载的过程会适当重建或者销毁内部的事件监听、子组件。…

这五本大模型书籍,让你从大模型零基础到精通,非常详细收藏我这一篇就够了

大模型&#xff08;Large Language Models, LLMs&#xff09;是近年来人工智能领域的一大热点&#xff0c;它们在自然语言处理、对话系统、内容生成等多个方面展现出了强大的能力。随着技术的发展&#xff0c;市面上出现了许多介绍大模型理论与实践的书籍&#xff0c;为研究人员…

碳性电池和碱性电池的区别

碳性电池和碱性电池是两种常见的电池类型&#xff0c;它们在多个方面存在显著的差异。下面是它们之间的一些主要区别&#xff1a; 1. 化学组成 碳性电池&#xff0c;又称为锌锰电池。通常使用二氧化锰作为正极材料&#xff0c;锌作为负极材料&#xff0c;并且电解质为酸性的NH4…

产品推介——SOP4 随机相位可控硅光耦KLM305X

产品描述Product Description KLM305X 系列由一个砷化镓红外发光二极管和一个单晶硅芯片的随机相位光电双向晶闸管组成的可控硅光电耦合器&#xff0c;它被设计用于连接电子控制和功率双向可控硅开关&#xff0c;以控制115至240VAC工作电压下的电阻和感应负载。 功能图Functi…

【一文读懂】C#如何实现通用的排序功能

目录 通用排序功能 1.升序 2.降序 测试 1.测试代码 2.测试结果 本篇文章来分享一下C#如何实现通用的排序功能。在项目中经常会使用到排序的方法&#xff0c;那如何使排序方法更加通用呢&#xff1f;可以通过泛型&#xff0c;接口&#xff0c;委托来实现。 通用排序功能…

【移植】Combo解决方案之W800芯片移植案例

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 本方案基于 OpenHarmony LiteOS-M 内核&#xff0c;使用联盛德 W80…

2024年项目经理不能错过的开源项目管理系统大盘点:全面指南

在2024年&#xff0c;随着项目管理领域的不断发展&#xff0c;开源项目管理系统成为了项目经理们提升工作效率的利器。本文将全面盘点几款备受推荐的开源项目管理系统&#xff0c;帮助项目经理们找到最佳选择&#xff0c;不容错过。 在项目管理日益复杂的今天&#xff0c;开源项…

Linux应急响应技巧整理

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330&scene21#wechat_redirect 《网安面试指南》…

是否是递增的字符串(c语言)

1 其功能是:判断t所指字符串中的字母是否由连续递增字母序列组成 (字符串长度大于等于2)。 例如:字符串: uvwxyz满足要求; 而字符串: uvxwyz不满足要求。 2.我们先输入字符串&#xff0c;然后进行判断是否a[i]1a[i1]&#xff0c;如果是则是由连续字母组成的字符串&#xf…

【性能优化】低配starRocks常驻内存优化

背景说明 由于服务器的实际资源小于starRocks官方的配置&#xff0c;导致starRocks在无任务的情况下&#xff0c;常驻内存偏高&#xff0c;可用于查询的资源变小。 官方文档 实际部署的集群一般是4C8G和8C16G&#xff0c;be的配置不达标 为了解决单次查询内存不足的问题&…