JWT:json web token是一种无状态的权限认证方式,一般用于前后端分离,时效性比较极端的权限校验,jwt模式获取token跟前面的客户端、密码、授权码模式是一样的,只是需要配置秘钥。
新建认证服务器:springcloud-micro-jwt
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-oauth2artifactId>
dependency>
不需要添加
/**
* JWT方式配置类
* */
@Configuration
@EnableAuthorizationServer
public class OAuth2JwtConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private DataSource dataSource;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 配置token的存储方式为JwtTokenStore
endpoints.tokenStore(tokenStore())
// 配置用于JWT私钥加密的增强器
.tokenEnhancer(jwtTokenEnhancer())
// 配置安全认证管理
.authenticationManager(authenticationManager)
.userDetailsService(myUserDetailsService);
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
@Bean
protected JwtAccessTokenConverter jwtTokenEnhancer() {
// 配置jks文件
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("springcloud-micro-jwt.jks"), "123456".toCharArray());
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("springcloud-micro-jwt"));
return converter;
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
// 对获取Token的请求不再拦截
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");// 验证获取Token的验证信息
}
}
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserServiceDetail userServiceDetail;
@Override
public @Bean
AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();//关闭CSRF
// .exceptionHandling()
// .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
// .and()
// .authorizeRequests()
// .antMatchers("/oauth/**").permitAll()
.antMatchers("/**").authenticated()
// .and()
// .httpBasic();
http.requestMatchers().anyRequest()
.and()
.authorizeRequests()
.antMatchers("/oauth/**").permitAll();
}
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
public static NoOpPasswordEncoder noOpPasswordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userServiceDetail).passwordEncoder(passwordEncoder());
}
}
access(String) 如果给定的SpEL表达式计算结果为true,就允许访问
anonymous() 允许匿名用户访问
authenticated() 允许认证的用户进行访问
denyAll() 无条件拒绝所有访问
fullyAuthenticated() 如果用户是完整认证的话(不是通过Remember-me功能认证的),就允许访问
hasAuthority(String) 如果用户具备给定权限的话就允许访问
hasAnyAuthority(String…)如果用户具备给定权限中的某一个的话,就允许访问
hasRole(String) 如果用户具备给定角色(用户组)的话,就允许访问/
hasAnyRole(String…) 如果用户具有给定角色(用户组)中的一个的话,允许访问.
hasIpAddress(String 如果请求来自给定ip地址的话,就允许访问.
not() 对其他访问结果求反.
permitAll() 无条件允许访问
rememberMe() 如果用户是通过Remember-me功能认证的,就允许访问
...
新建业务客户端项目:springcloud-micro-jwt-web
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-oauth2artifactId>
dependency>
#spring:
# security:
# user:
# name: admin
# password: admin
# 服务鉴权配置
security:
oauth2:
resource:
jwt:
key-uri: http://localhost:8081/jwt/oauth/token_key
service: uni-meta-provider
client:
access-token-validity-seconds: 36000
clientId: pc
client-secret: 123456
access-token-uri: http://localhost:8081/oauth/token
grant-type: password # refresh_token client_credentials password authorization_code
scope: all
@Configuration
public class JwtConfig {
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Bean
@Qualifier("tokenStore")
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter);
}
@Bean
public JwtAccessTokenConverter jwtTokenEnhancer() {
// 用作JWT转换器
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
Resource resource = new ClassPathResource("public.cert");
String publicKey;
try {
publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
} catch (IOException e) {
throw new RuntimeException(e);
}
//设置公钥
converter.setVerifierKey(publicKey);
return converter;
}
}
资源服务器开启@EnableResourceServer
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/user/login","/user/register").permitAll()
.antMatchers("/**").authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
}
}
...
cd到jdk的bin目录执行该指令,会在bin目录下生成xxx.jks文件,把该文件放到认证服务工程里面的resources目录下:
管理员身份运行cmd执行命令:keytool -genkeypair -alias springcloud-micro-jwt -validity 3650 -keyalg RSA -dname "CN=jwt,OU=jtw,O=jwt,L=zurich,S=zurich, C=CH" -keypass 123456 -keystore springcloud-micro-jwt.jks -storepass 123456
生成如下文件:springcloud-micro-jwt.jks
然后将该文件放到认证服务器的resources目录下。
keytool -list -rfc --springcloud-micro-jwt.jks | openssl x509 -inform pem -pubkey
把生成的公钥内容放到public.cert文件中,内容如下:
把公钥文件放到客户端的resources目录下。
访问地址:
密码模式获取token:
Jwt的token信息分成三个部分,用“.”号分割的。
第一部分:头信息,通过base64加密生成。
第二部分:有效载荷,通过base64加密生成。
第三部分:签名,根据头信息中的加密算法通过,RSA(base64(头信息) + “.” + base64(有效载荷))生成的第三部分内容。
可以到jwt的官网看看这三部分信息的具体内容:jwt官网jwt.io