SpringSecurity

2022-9-3 大约 2 分钟

# SpringSecurity

# 认证(Authentication)

# 未注入security配置默认过滤器

img_1.png

# security + jwt

原理:放行/login请求,登录后返回jwt token,主配置类中追加过滤器判断jwt是否有效,若无效直接被exceptionHandling捕获异常, 若有效则获取jwt中用户信息(不包含密码)及获取该用户redis中的权限,通过UsernamePasswordAuthenticationToken构建对象设置到上下文中。

主配置类

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .and()
                //禁止网页iframe
                .headers().frameOptions().disable().and()
                //任何请求需要身份认证
                .authorizeRequests().anyRequest().authenticated().and()
                //允许跨域
                .cors().configurationSource(new corsFilter()).and()
                //关闭跨站请求防护
                .csrf().disable()
                //前后端分离采用JWT 不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                //权限拒绝处理类
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
                //认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                //添加JWT认证过滤器
                .addFilter(new JwtAuthenticationTokenFilter())
                //可以通过api
                .antMatchers("/login").permitAll();
    }

}
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

jwt过滤器

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
    @Autowired
    private TokenService tokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException
    {
        LoginUser loginUser = tokenService.getLoginUser(request);
        // 每一次请求Authentication为null
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityContextHolder.getContext().getAuthentication()))
        {
            tokenService.verifyToken(loginUser);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

生成的过滤器

img_1.png

# 授权(Authorization)

# 原理:根据UsernamePasswordAuthenticationToken配置用户权限,通过以下注解对api进行限制

  • anyRequest | 匹配所有请求路径
  • access | SpringEl表达式结果为true时可以访问
  • anonymous | 匿名可以访问
  • denyAll | 用户不能访问
  • fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
  • hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
  • hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
  • hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
  • hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
  • hasRole | 如果有参数,参数表示角色,则其角色可以访问
  • permitAll | 用户可以任意访问
  • rememberMe | 允许通过remember-me登录的用户访问
  • authenticated | 用户登录后可访问

# 使用例子

@RestController
@RequestMapping("/money")
public class MoneyController extends BaseController {
    @GetMapping("/info/{id}")
    @PreAuthorize("hasAuthority('money:update')")
    public Result info(@PathVariable("id") Long id) {
        Money money = moneyService.findById(id);

        return Result.succ(money);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
上次编辑于: 2022年9月20日 12:18