foreword
I have written before using springsecurity to build an authentication service SpringSecurity+Oauth2: password authorization mode to obtain Token (MongoDB+JWT) . This article writes about how to build a resource service. Only the authenticated token can be accessed.
operate
1. Configure the jar package of Pom.xml that references spring-cloud-security
and oauth2
2. Configure the main class @EnableResourceServer
annotation to enable resource services
3. Create JWTTokenStoreConfig
class, configure and parse token
4. Create ResourceServerConfiguration
class configuration access rights and custom exceptions
5. Custom springsecurity
exception information ( note: the custom exceptions of authentication and resource services are unified and there is no difference, which will be explained below )
1. Configure the jar package of Pom.xml reference spring-cloud-security
and oauth2
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
2. Configure the main class @EnableResourceServer annotation to enable resource services
@SpringBootApplication
// 资源保护服务
@EnableResourceServer
// 服务发现
@EnableDiscoveryClient
@EnableFeignClients
@RefreshScope
public class Xxxx {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public static void main(String[] args) {
SpringApplication.run(Xxxx.class, args);
}
}
3. Create JWTTokenStoreConfig
class, configure and parse token
@Configuration
public class JWTTokenStoreConfig {
@Autowired
private ServiceConfig serviceConfig;
//JWT
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
//JWT
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
//JWT
// 从配置文件中获取jwt key,然后自己解析token是否有效,
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(serviceConfig.getJwtSigningKey());
return converter;
}
}
4. Create ResourceServerConfiguration
class configuration access rights and custom exceptions
@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
authenticationEntryPoint.setExceptionTranslator(new CustomOAuthWebResponseExceptionTranslator());
resources.authenticationEntryPoint(authenticationEntryPoint);
OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler = new OAuth2AccessDeniedHandler();
oAuth2AccessDeniedHandler.setExceptionTranslator(new CustomOAuthWebResponseExceptionTranslator());
resources.accessDeniedHandler(oAuth2AccessDeniedHandler);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 放开/sendRegisterEmailMessage,不需要校验token
.antMatchers("/websocket/**").permitAll()
.antMatchers("/info/**").permitAll()
.anyRequest().authenticated();
}
}
5. Custom springsecurity
Exception information
Create CustomOAuthException
class
@JsonSerialize(using = CustomOAuthExceptionSerializer.class)
public class CustomOAuthException extends OAuth2Exception {
private static Logger log = LoggerFactory.getLogger(CustomOAuthException.class);
private String oAuth2ErrorCode;
private int httpErrorCode;
public CustomOAuthException(String msg, String oAuth2ErrorCode, int httpErrorCode) {
super(msg);
this.oAuth2ErrorCode = oAuth2ErrorCode;
this.httpErrorCode = httpErrorCode;
}
}
Create CustomOAuthExceptionSerializer
class
public class CustomOAuthExceptionSerializer extends StdSerializer<CustomOAuthException> {
private static Logger log = LoggerFactory.getLogger(CustomOAuthExceptionSerializer.class);
protected CustomOAuthExceptionSerializer() {
super(CustomOAuthException.class);
}
@Override
public void serialize(CustomOAuthException e, JsonGenerator generator, SerializerProvider serializerProvider) throws IOException {
generator.writeStartObject();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
generator.writeObjectField("error",e.getOAuth2ErrorCode());
generator.writeObjectField("status", e.getHttpErrorCode());
generator.writeObjectField("message", e.getMessage());
generator.writeObjectField("path", request.getServletPath());
generator.writeObjectField("timestamp", (new Date()).getTime());
if (e.getAdditionalInformation() != null) {
for (Map.Entry<String, String> entry : e.getAdditionalInformation().entrySet()) {
String key = entry.getKey();
String add = entry.getValue();
generator.writeObjectField(key, add);
}
}
generator.writeEndObject();
}
}
Create CustomOAuthWebResponseExceptionTranslator
class
@Component
public class CustomOAuthWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator {
private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
private static Logger log = LoggerFactory.getLogger(CustomOAuthWebResponseExceptionTranslator.class);
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
ResponseEntity<OAuth2Exception> translate = super.translate(e);
OAuth2Exception body = translate.getBody();
CustomOAuthException customOauthException = new CustomOAuthException(body.getMessage(),body.getOAuth2ErrorCode(),body.getHttpErrorCode());
ResponseEntity<OAuth2Exception> response = new ResponseEntity<>(customOauthException, translate.getHeaders(), translate.getStatusCode());
return response;
}
}
Finally, if the username or password is incorrect, the following error message is returned:
{
timestamp: 1658149719489,
path: '/oauth/token',
error: 'invalid_request',
message: '用户名或密码错误'
status: 400
}
If the token is wrong, the following error message is returned:
{
timestamp: 1658149719489,
path: '/oauth/token',
error: 'invalid_request',
message: 'token错误或过期'
status: 400
}
If the refresh_token is wrong, the following error message is returned:
{
timestamp: 1658149719489,
path: '/oauth/token',
error: 'invalid_request',
message: 'refresh_token错误或过期'
status: 400
}
Directory structure of resource services
Directory Structure of Authentication Service
Summarize
1. When the exception information that comes with springsecurity does not meet your needs, you must customize the return error information
2. If the error code returned by the error message is 401, then 401 will still be returned. If you think 401 is not very good, you can set it yourself
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。