JWT分为三部分:头部、载荷、签名。如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE3MDU5OTQ0MzgsImF1dGhvcml0aWVzIjpbIlJPTEVfYWRtaW4iXSwianRpIjoiM2RiYjVkNGUtN2Q3My00ODI3LTlkOGYtMmI3OGVmMmVmZTExIiwiY2xpZW50X2lkIjoiYzEifQ.
eAVj9_lLpUC99jJbLwV2OwNrPvjGqoKgtHm5_jlgqBg
头部定义了JWT基本信息,如类型和签名
载荷包含了一些基本信息(签发时间、过期时间),另外还可以添加一些自定义的信息,比如用户的部分信息。
签名部分将前两个字符串用.连接后,使用头部定义的加密算法,利用密钥进行签名,并将签名信息附在最后。
OAuth2.0分为认证授权中心、资源服务,认证中心用于颁发令牌,资源服务解析令牌并且提供资源。
令牌配置
@Configuration
public class TokenConfig {
/**
* 对称密钥,资源服务器使用该密钥来验证
*/
private final static String SIGNING_KEY = "uaa123";
@Bean
public TokenStore tokenStore(){
//JWT令牌存储方案
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(SIGNING_KEY);
return converter;
}
/* @Bean
public TokenStore tokenStore() {
//使用内存存储令牌(普通令牌)
return new InMemoryTokenStore();
}*/
}
1、JwtAccessTokenConverter
令牌增强类,用于JWT令牌和OAuth身份进行转换
2、TokenStore
令牌的存储策略,这里使用的是JwtTokenStore,使用JWT的令牌生成方式,其实还有以下两个比较常用的方式
RedisTokenStore:将令牌存储到Redis中,此种方式相对于内存方式来说性能更好。
JdbcTokenStore:将令牌存储到数据库中,需要新建对应的表。
3、SIGNING_KEY
JWT签名的密钥,这里使用的是对称加密,资源服务也要使用相同的密钥进行校验和解析JWT令牌。
认证授权中心
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private JwtAccessTokenConverter accessTokenConverter;
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthenticationManager authenticationManager;
//客户端详情服务,也就是configure(ClientDetailsServiceConfigurer clients)方法
@Autowired
private ClientDetailsService clientDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//这里是第三方合作用户的客户id,密钥的配置
//使用in-memory存储
clients.inMemory()
// 设置我们接受的客户端的编号
.withClient("c1")
// secret密码
.secret(passwordEncoder().encode("123456"))
// 认证模式:password模式
.authorizedGrantTypes("password", "refresh_token")
// token的过期时间
.accessTokenValiditySeconds(1800)
// 资源id
.resourceIds("res1")
//作用域 读写 针对资源的操作权限
.scopes("all");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 令牌管理服务
*/
@Bean
public AuthorizationServerTokenServices tokenService() {
DefaultTokenServices service = new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService);
service.setSupportRefreshToken(true);// 支持刷新
service.setTokenStore(tokenStore);// 令牌存储
//设置令牌增强,使用JwtAccessTokenConverter进行转换
service.setTokenEnhancer(accessTokenConverter);
// 令牌默认有效期2小时
service.setAccessTokenValiditySeconds(7200);
// 刷新令牌默认有效期3天
service.setRefreshTokenValiditySeconds(259200);
return service;
}
/**
* 配置令牌访问的端点
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
// 指定认证管理器
.authenticationManager服务器托管网(authenticationManager)
// 授权码模式需要
.authorizationCodeServices(authorizationCodeServices())
// 令牌管理服务
.tokenServices(tokenService())
// jwt格式Token
.accessTokenConverter(accessTokenConverter)
// 允许post提交
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
/**
* 授权码服务器
*/
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
// 授权码模式的授权码采用内存方式存储
return new InMemoryAuthorizationCodeServices();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
// 提供公有密匙的端点,如果你使用JWT令牌的话, 允许
.tokenKeyAccess("permitAll()")
// oauth/check_token:用于资源服务访问的令牌解析端点,允许
.checkTokenAccess("permitAll()")
// 表单认证,申请令牌
.allowFormAuthenticationForClients();
}
令牌管理服务,使用的是DefaultTokenService这个实现类,其中可以配置令牌相关的内容,如access_token、refresh_token的过期时间,默认时间分别为12小时、30天。
设置令牌增强,使用JWT方式生成令牌,如下:
service.setTokenEnhancer(accessTokenConverter);
web安全配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(myUserDetailsService());
}
@Bean
public UserDetailsService myUserDetailsService() {
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
userDetailsService.createUser(User.withUsername("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("admin").build());
return userDetailsService;
}
}
UserDetailsServices使用内存方式保存,创建一个用户。
OAuth2.0资源服务
@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServer服务器托管网ConfigurerAdapter {
@Autowired
// 令牌存储策略
private TokenStore tokenStore;
// 授权服务的资源列表
public static final String RESOURCE_ID = "res1";
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
// 资源 id
.resourceId(RESOURCE_ID)
// // 令牌服务
// .tokenServices(tokenService())
// 令牌服务
.tokenStore(tokenStore)
.stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**")
// 所有的访问,授权访问都要是all,和认证服务器的授权范围一一对应
.access("#oauth2.hasScope('all')")
//去掉防跨域攻击
.and().csrf().disable()
//session管理
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
资源id和令牌服务配置到ResourceServerSecurityConfiguer中。
由于使用了JWT这种透明令牌,令牌本身携带着部分用户信息,不需要远程调用认证中心的接口校验令牌。
测试
1、使用密码模式获取令牌
可以看到已经成功返回了JWT令牌。
2、携带令牌调用资源服务
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 玩转Python:数据可视化,一个很高级的交互式Python库,附代码
在数据科学和分析的世界里,将数据可视化是至关重要的一步,它能帮助我们更好地理解数据,发现潜在的模式和关系。Python 提供了多种可视化工具,HvPlot 是其中一个出色的库,专为简单且高效的交互式可视化设计。 HvPlot 简介 HvPlot 是基于 Hol…