Spring Security添加权限认证

刚刚开通了一个公众号,会分享一些技术博客和自己觉得比较好的项目,同时会更新一些自己使用的工具和图书资料,后面会整理一些面试资料进行分享,觉得有兴趣的可以关注一下。
在这里插入图片描述


前言

最近开发的新需求中需要给前端的权限做验证,由于项目中统一引用的spring security,那么直接使用就好了。


问题

1.权限的配置是统一的,权限的配置不是使用的spring security提供的方式,而是结合了oauth2jwt的方式,解析到用户名之后再发送请求获取的。

2.azure提供的jwttoken解析的用户名不是我们需要的,而是azure生成的自己系统的用户id

解决

1.先看第二个问题,比较简单

经过debug发现,解析用户名的其实是JwtAuthenticationConverter,查看其方法,他默认是将sub作为了用户名。具体代码如下:

	private String principalClaimName = JwtClaimNames.SUB;

	@Override
	public final AbstractAuthenticationToken convert(Jwt jwt) {
		Collection<GrantedAuthority> authorities = extractAuthorities(jwt);

		String principalClaimValue = jwt.getClaimAsString(this.principalClaimName);
		return new JwtAuthenticationToken(jwt, authorities, principalClaimValue);
	}

那么需要找到这个bean是怎么配置的,设置一下这个principalClaimName 就OK了。

这个是在OAuth2ResourceServerConfigurer里面配置的,他先看容器里面有没有,没有的话自己new一个。具体代码如下:

	Converter<Jwt, ? extends AbstractAuthenticationToken> getJwtAuthenticationConverter() {
			if (this.jwtAuthenticationConverter == null) {
				if (this.context.getBeanNamesForType(JwtAuthenticationConverter.class).length > 0) {
					this.jwtAuthenticationConverter = this.context.getBean(JwtAuthenticationConverter.class);
				}
				else {
					this.jwtAuthenticationConverter = new JwtAuthenticationConverter();
				}
			}
			return this.jwtAuthenticationConverter;
		}

那就简单了,直接生命一个Bean放容器里就好了。

	@Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setPrincipalClaimName("username");
        return converter;
    }

2.再来看第一个问题

一般来说,权限信息不会变更那么频繁,也不可能每次请求我都去重新查一下权限,那么就必须缓存下来,能增加请求速度。
但是由于这是jwtspring security,仅缓存时不够的,必须写入spring security认证的数据当中。就是JwtAuthenticationToken。请求还得存储,本来想的是通过一个请求,在service中存储并写权限,那这样的话请求其他接口就不会生效,
所以必须放在spring security的请求链里面。

配置如下:

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, WebSecurityResponseExceptionHandler webSecurityResponseExceptionHandler) throws Exception {
        http
                .exceptionHandling()
                .authenticationEntryPoint(webSecurityResponseExceptionHandler).accessDeniedHandler(webSecurityResponseExceptionHandler)
                .and()
                .anyRequest().authenticated().and().sessionManagement()
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .addFilterAfter(new PermissionProviderFilter(), BearerTokenAuthenticationFilter.class);
        return http.build();
    }

filter代码如下,其实就是照着葫芦画瓢:

    private class PermissionProviderFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            String requestURI = ((HttpServletRequest) request).getRequestURI();
            if (requestURI.startsWith(CConstant.API_BACKEND_URL)) {
                chain.doFilter(request, response);
                return;
            }
            JwtAuthenticationToken oldAuthentication= (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
            if (Objects.isNull(oldAuthentication)) {
                chain.doFilter(request, response);
                return;
            }
            String username = ((Jwt) oldAuthentication.getPrincipal()).getClaim("username");

            List<GrantedAuthority> authorities = CacheUtils.getCache(username);
            if (Objects.isNull(authorities)) {
                List<GrantedAuthority> authorities = userService.userDetail(username);
                CacheUtils.setCache(username, authorities);
            }
            JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(oldAuthentication.getToken(), authorities, username);
            jwtAuthenticationToken.setDetails(oldAuthentication.getDetails());
            jwtAuthenticationToken.eraseCredentials();
            SecurityContextHolder.getContext().setAuthentication(jwtAuthenticationToken);
            chain.doFilter(request, response);
        }
    }

打完收工!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦幻D开始

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值