做基于Spring Security Jwt认证的Starter包

本文介绍了如何创建一个基于Spring Security的JWT认证Starter包,实现一键开启JWT认证功能。内容包括JWT的背景、Spring Security的核心类解释、Starter包实现的认证流程,以及详细的步骤解析,旨在简化前后端分离项目的用户身份管理。最后提供了项目源码的GitHub链接。
摘要由CSDN通过智能技术生成

以前老的项目大多采用的是session进行用户身份的管理,目前很多公司的项目都是前后端分离, 这样使用session 成本就会变高,然后多数项目会采用Jwt进行用户的身份的管理。

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。有不清楚的同学可以先看看者篇文章:10分钟了解JSON Web令牌(JWT)

今天要做的事就是将Jwt认证和授权的过程封装成一个Springboot 的Stater包,只需要使用EnableJwtSecurity注解,就可以一键开启Jwt认证功能,无需在每个项目都拷贝同样的认证代码,非常的麻烦。代码已经放在github上,链接地址在文末,有兴趣的可以亲自使用一下,欢迎提出您的宝贵意见。
该Starter包含的功能
1、支持白名单过滤功能
2、支持配置token刷新时间
3、支持生成随机盐的方式生成Jwt(默认是使用的固定的盐)
4、最重要的当然是Jwt认证功能啦

接下来我们开始讲解该Starter的认证思路,篇幅有点长,请耐心阅读

Spring Security 核心类简介

AuthenticationManager, 用户认证的管理类,所有的认证请求(比如login)都会通过提交一个token给AuthenticationManager的authenticate()方法来实现。当然事情肯定不是它来做,具体校验动作会由AuthenticationManager将请求转发给具体的实现类来做。根据实现反馈的结果再调用具体的Handler来给用户以反馈。这个类基本等同于shiro的SecurityManager。

AuthenticationProvider, 认证的具体实现类,一个provider是一种认证方式的实现,比如提交的用户名密码我是通过和DB中查出的user记录做比对实现的,那就有一个DaoProvider;如果我是通过CAS请求单点登录系统实现,那就有一个CASProvider。这个是不是和shiro的Realm的定义很像?基本上你可以帮他们当成同一个东西。按照Spring一贯的作风,主流的认证方式它都已经提供了默认实现,比如DAO、LDAP、CAS、OAuth2等。。

UserDetailService, 用户认证通过Provider来做,所以Provider需要拿到系统已经保存的认证信息,获取用户信息的接口spring-security抽象成UserDetailService。虽然叫Service,但是我更愿意把它认为是我们系统里经常有的UserDao。

AuthenticationToken, 所有提交给AuthenticationManager的认证请求都会被封装成一个Token的实现,比如最容易理解的UsernamePasswordAuthenticationToken。这个就不多讲了,连名字都跟Shiro中一样。

SecurityContext,当用户通过认证之后,就会为这个用户生成一个唯一的SecurityContext,里面包含用户的认证信息Authentication。通过SecurityContext我们可以获取到用户的标识Principle和授权信息GrantedAuthrity。在系统的任何地方只要通过SecurityHolder.getSecruityContext()就可以获取到SecurityContext。在Shiro中通过SecurityUtils.getSubject()到达同样的目的。

##Spring Security Filter

Spring Security 的底层是通过一系列的 Filter 来管理的,每个 Filter 都有其自身的功能,而且各个 Filter 在功能上还有关联关系,所以它们的顺序也是非常重要的。

Filter 顺序
1.Spring Security 已经定义了一些 Filter,不管实际应用中你用到了哪些,它们应当保持如下顺序。

2.ChannelProcessingFilter,如果你访问的 channel 错了,那首先就会在 channel 之间进行跳转,如 http 变为 https。

3.SecurityContextPersistenceFilter,这样的话在一开始进行 request 的时候就可以在 SecurityContextHolder 中建立一个 SecurityContext,然后在请求结束的时候,任何对 SecurityContext 的改变都可以被 copy 到 HttpSession。

4.ConcurrentSessionFilter,因为它需要使用 SecurityContextHolder 的功能,而且更新对应 session 的最后更新时间,以及通过 SessionRegistry 获取当前的 SessionInformation 以检查当前的 session 是否已经过期,过期则会调用 LogoutHandler。

认证处理机制,如 UsernamePasswordAuthenticationFilter,CasAuthenticationFilter,BasicAuthenticationFilter 等,以至于 SecurityContextHolder 可以被更新为包含一个有效的 Authentication 请求。

5.SecurityContextHolderAwareRequestFilter,它将会把 HttpServletRequest 封装成一个继承自 HttpServletRequestWrapper 的 SecurityContextHolderAwareRequestWrapper,同时使用 SecurityContext 实现了 HttpServletRequest 中与安全相关的方法。

6.JaasApiIntegrationFilter,如果 SecurityContextHolder 中拥有的 Authentication 是一个 JaasAuthenticationToken,那么该 Filter 将使用包含在 JaasAuthenticationToken 中的 Subject 继续执行 FilterChain。

7.RememberMeAuthenticationFilter,如果之前的认证处理机制没有更新 SecurityContextHolder,并且用户请求包含了一个 Remember-Me 对应的 cookie,那么一个对应的 Authentication 将会设给 SecurityContextHolder。

8.AnonymousAuthenticationFilter,如果之前的认证机制都没有更新 SecurityContextHolder 拥有的 Authentication,那么一个 AnonymousAuthenticationToken 将会设给 SecurityContextHolder。

9.ExceptionTransactionFilter,用于处理在 FilterChain 范围内抛出的 AccessDeniedException 和 AuthenticationException,并把它们转换为对应的 Http 错误码返回或者对应的页面。

10.FilterSecurityInterceptor,保护 Web URI,并且在访问被拒绝时抛出异常。

  • 以下是Spring Security 大致的认证流程:
    认证流程

##Jwt 认证流程

看了以上的知识我们要做的无非就是定义一个Filter用于过滤需要认证的请求,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot可以很方便地整合Spring SecurityJWT(JSON Web Token)。 首先,需要在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 然后,需要创建一个Security配置类,用于配置Spring SecurityJWT: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { // 配置用户认证方式 } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf().disable() .authorizeRequests().antMatchers("/authenticate").permitAll(). anyRequest().authenticated().and(). exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } } ``` 在上面的配置类中,需要注入JwtAuthenticationEntryPoint和JwtRequestFilter两个类。其中,JwtAuthenticationEntryPoint用于处理未经授权的请求,JwtRequestFilter用于验证JWT并将用户信息添加到Spring Security上下文中。 接下来,需要创建一个JwtTokenUtil类,用于生成和验证JWT: ```java @Component public class JwtTokenUtil { private static final String SECRET_KEY = "secret"; public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); return Jwts.builder().setClaims(claims).setSubject(userDetails.getUsername()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) .signWith(SignatureAlgorithm.HS512, SECRET_KEY).compact(); } public boolean validateToken(String token, UserDetails userDetails) { final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } private boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } private Date getExpirationDateFromToken(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration(); } private String getUsernameFromToken(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject(); } } ``` 在上面的类中,需要设置一个密钥,用于生成和验证JWT。generateToken方法用于生成JWT,validateToken方法用于验证JWT是否有效。 最后,需要创建一个JwtAuthenticationEntryPoint类和一个JwtRequestFilter类。JwtAuthenticationEntryPoint类用于处理未经授权的请求,JwtRequestFilter类用于验证JWT并将用户信息添加到Spring Security上下文中。 以上就是整合Spring SecurityJWT的基本步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值