**
1 什么是jwt?
这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
1 header
头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。
{“typ”:“JWT”,“alg”:“HS256”}
2 载荷(playload)
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
3 签证(signature)
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
**
2 springboot+spring-security 框架的搭建
1 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Security依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- MybatisPlus 核心库 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 引入阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<!-- StringUtilS工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<!-- JSON工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.45</version>
</dependency>
<!-- JWT依赖 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
</configuration>
</plugin>
</plugins>
</build>
2 securityConfig.java 核心配置类
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启权限注解,默认是关闭的
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 自定义登录成功处理器
*/
@Autowired
private UserLoginSuccessHandler userLoginSuccessHandler;
/**
* 自定义登录失败处理器
*/
@Autowired
private UserLoginFailureHandler userLoginFailureHandler;
/**
* 自定义注销成功处理器
*/
@Autowired
private UserLogoutSuccessHandler userLogoutSuccessHandler;
/**
* 自定义暂无权限处理器
*/
@Autowired
private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
/**
* 自定义未登录的处理器
*/
@Autowired
private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
/**
* 自定义登录逻辑验证器
*/
@Autowired
private UserAuthenticationProvider userAuthenticationProvider;
/**
* 加密方式
* @Author Sans
* @CreateTime 2019/10/1 14:00
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 注入自定义PermissionEvaluator
*/
@Bean
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler(){
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(new UserPermissionEvaluator());
return handler;
}
/**
* 配置登录验证逻辑
*/
@Override
protected void configure(AuthenticationManagerBuilder auth){
//这里可启用我们自己的登陆验证逻辑
auth.authenticationProvider(userAuthenticationProvider);
}
/**
* 配置security的控制逻辑
* @Author Sans
* @CreateTime 2019/10/1 16:56
* @Param http 请求
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 不进行权限验证的请求或资源(从配置文件中读取)
.antMatchers(JWTConfig.antMatchers.split(",")).permitAll()
// 其他的需要登陆后才能访问
.anyRequest().authenticated()
.and()
// 配置未登录自定义处理类
.httpBasic().authenticationEntryPoint(userAuthenticationEntryPointHandler)
.and()
// 配置登录地址
.formLogin()
.loginProcessingUrl("/login/userLogin")
// 配置登录成功自定义处理类
.successHandler(userLoginSuccessHandler)
// 配置登录失败自定义处理类
.failureHandler(userLoginFailureHandler)
.and()
// 配置登出地址
.logout()
.logoutUrl("/login/userLogout")
// 配置用户登出自定义处理类
.logoutSuccessHandler(userLogoutSuccessHandler)
.and()
// 配置没有权限自定义处理类
.exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler)
.and()
// 开启跨域
.cors()
.and()
// 取消跨站请求伪造防护
.csrf().disable();
// 基于Token不需要session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// 禁用缓存
http.headers().cacheControl();
// 添加JWT过滤器
http.addFilter(new JWTAuthenticationTokenFilter(authenticationManager()));
}
}
3 JWTAuthenticationTokenFilter.java jwt的过滤器
@Slf4j
public class JWTAuthenticationTokenFilter extends BasicAuthenticationFilter {
public JWTAuthenticationTokenFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 获取请求头中JWT的Token
String tokenHeader = request.getHeader(JWTConfig.tokenHeader);
if (null!=tokenHeader && tokenHeader.startsWith(JWTConfig.tokenPrefix)) {
try {
// 截取JWT前缀
String token = tokenHeader.replace(JWTConfig.tokenPrefix, "");
// 解析JWT
Claims claims = Jwts.parser()
.setSigningKey(JWTConfig.secret)
.parseClaimsJws(token)
.getBody();
// 获取用户名
String username = claims.getSubject();
String userId=claims.getId();
if(!StringUtils.isEmpty(username)&&!StringUtils.isEmpty(userId)) {
// 获取角色
List<GrantedAuthority> authorities = new ArrayList<>();
String authority = claims.get("authorities").toString();
if(!StringUtils.isEmpty(authority)){
List<Map<String,String>> authorityMap = JSONObject.parseObject(authority, List.class);
for(Map<String,String> role : authorityMap){
if(!StringUtils.isEmpty(role)) {
authorities.add(new SimpleGrantedAuthority(role.get("authority")));
}
}
}
//组装参数
SelfUserEntity selfUserEntity = new SelfUserEntity();
selfUserEntity.setUsername(claims.getSubject());
selfUserEntity.setUserId(Long.parseLong(claims.getId()));
selfUserEntity.setAuthorities(authorities);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(selfUserEntity, userId, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (ExpiredJwtException e){
log.info("Token过期");
} catch (Exception e) {
log.info("Token无效");
}
}
filterChain.doFilter(request, response);
return;
}
}