1.说明
1.1 背景
慢慢构造一个微型的商城demo。使用的技术栈是SpringBoot+SpringCloud; 各个服务间的接口调用是有权限验证的。每个请求头包含token,通过token来 校验该请求是否合法
1.2 使用技术
-
springBoot 基础框架
-
SpringCloud
- eureka 服务与服务的注册中心
- Feign 负责服务间的调用
- zuul 向外暴露的服务网关
-
Spring Security 安全框架
-
ORM
- mybatis plus 对mybatis的进一步封装
-
redis 应用缓存、接口数据缓存
-
zookeeper 注册中心
-
rabbitMQ 消息队列
-
JWT 结合Spring Security使用,实现服务之间的鉴权。Spring Security负责请求的过滤拦截以及赋权, JWT负责判断该token是否过期
1.3 项目结构
├── README.md
├── demo-cache 缓存模块
├── demo-common 公共模块,包括切面,token认证等一些公共方法
├── demo-eureka 注册中心
├── demo-gateway 网关
├── demo-message 消息模块(kafka)
├── demo-parent.iml
├── demo-product 产品模块
├── demo-user 用户模块
├── demo.sql 初始化sql
└── pom.xml
1.4 JWT认证
1.4.1 JWT的认证流程
1.4.2 代码实现
- SpringSecurity配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private UserDetailsService userDetailService;
public SecurityConfig() {
super();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
// ***注入自定义的provider ***,在权限验证的时候后实际走的是 CustomAuthenticationProvider.authenticate
auth.authenticationProvider(new CustomAuthenticationProvider(userDetailService, bCryptPasswordEncoder()));
auth.userDetailsService(userDetailService).passwordEncoder(bCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//禁用 csrf
http.cors().and().csrf().disable().authorizeRequests()
//允许以下请求
.antMatchers("/login/**").permitAll()
// 所有请求需要身份认证
.anyRequest().authenticated()
.and()
// authenticationManager() 从IOC容器中获取。实际就是用户自定义注入的 CustomAuthenticationProvider
//拦截登录操作,
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
//拦截每一个请求,验证token是否有效
.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
}
}
- 登录过滤拦截
这里需要注意的是,获取登录名、密码默认是通过get方式获取的,而且键名也是一定的 如果是从json中获取还需要将request的请求参数转换为json数据
/**
* token信息