我创建了一个Spring Boot 2应用程序,该应用程序集成了SpringFox Swagger 2.8.0和用于身份验证和授权的隐式Oauth2 Grant。
该代码运行正常,但是当我单击“授权”按钮时,它将重定向到
,但显示访问被拒绝,如下所示。
我的完整项目可在 GitHub
中找到MainApplication.java
@EnableSwagger2
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@RestController
public class MainApplication /*extends WebMvcConfigurerAdapter*/
{
public static void main(String[] args)
{
SpringApplication.run(MainApplication.class, args);
}
@RequestMapping("/user")
public Principal user(Principal user) {
return user;
}
@Bean
SecurityConfiguration security() {
return SecurityConfigurationBuilder.builder()//<19>
.clientId("test-app-client-id")
.build();
}
@Bean
SecurityScheme oauth() {
List<GrantType> grantTypes = new ArrayList<>();
ImplicitGrant implicitGrant = new ImplicitGrant(new LoginEndpoint("http://localhost:8080/oauth/authorize"),"access_code");
grantTypes.add(implicitGrant);
List<AuthorizationScope> scopes = new ArrayList<>();
scopes.add(new AuthorizationScope("read","Read access on the API"));
return new OAuthBuilder()
.name("SECURITY_SCHEME_OAUTH2")
.grantTypes(grantTypes)
.scopes(scopes)
.build();
}
@Bean
public Docket docket()
{
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage(getClass().getPackage().getName()))
.paths(PathSelectors.any())
.build()
.securitySchemes(Collections.singletonList(oauth()))
.apiInfo(generateApiInfo());
}
private ApiInfo generateApiInfo()
{
return new ApiInfo("Sample Service", "This service is to check Sample Service.", "Version 1.0",
"Sample Service", "123@test.com", "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0");
}
}
我添加了来自 @AlexanderPetrov 的安全性和建议的密码编码器配置。一切正常,当我添加@EnableResourceServer
时,登录屏幕显示访问此资源需要完整身份验证,如下所示
有人可以帮我吗
答案 0 :(得分:1)
您需要在代码中进行以下更改
此外,如果我们使用隐式流令牌,则会通过授权url而非令牌url生成令牌。因此,您需要将“ / oauth / token”更改为“ oauth / authorize”。
下的配置方法@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/oauth/authorize").authenticated()
.and()
.authorizeRequests().anyRequest().permitAll()
.and()
.formLogin().permitAll()
.and()
.csrf().disable();
}
在SecurityConfig
类中添加密码编码器,并在globalUserDetails
方法中调用它以对用户密码进行编码。编码器是必需的,因为您在内存中使用密码。因此,如果没有密码编码器,应用程序将失败并显示错误:
Encoded password does not look like BCrypt
下面的代码片段
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder passwordEncoder = passwordEncoder();
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).
withUser("bill").password(passwordEncoder.encode("abc123")).roles("ADMIN").and()
.withUser("$2a$10$TT7USzDvMxMZvf0HUVh9p.er1GGnjNQzlcGivj8CivnaZf9edaz6C")
.password("$2a$10$TT7USzDvMxMZvf0HUVh9p.er1GGnjNQzlcGivj8CivnaZf9edaz6C").roles("USER");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
希望有帮助。我已经为您的项目创建了分支,但是由于403而无法将其推送。因此所有必需的代码都在我的答案中。
答案 1 :(得分:1)
启用资源服务器时,需要配置check_token URL,以便它可以访问OAuth2授权服务器并验证给定的access_token。
您可以执行以下操作:
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServerConfig extends GlobalMethodSecurityConfiguration {
@Value("${oauth.url.internal}") // e.g. http://localhost:8082/oauth
private String oauthUrl;
@Value("${oauth.client}")
private String oauthClient;
@Value("${oauth.secret}")
private String oauthSecret;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
@Primary
@Bean
public RemoteTokenServices tokenService() {
RemoteTokenServices tokenService = new RemoteTokenServices();
tokenService.setCheckTokenEndpointUrl(oauthUrl + "/check_token");
tokenService.setClientId(oauthClient);
tokenService.setClientSecret(oauthSecret);
return tokenService;
}
}
除此之外,您可能要忽略Swagger特定的端点:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**");
}
}
以防万一,这是我为带有OAuth2授权的Swagger实现的类:
@EnableSwagger2
@Configuration
public class SwaggerConfig implements WebMvcConfigurer {
private static final String BASE_PACKAGE = "com.somepackage.api";
@Value("${oauth.url}") // Make sure this is an external URL, i.e. accessible from Swagger UI
private String oauthUrl;
@Value("${swagger.scopes}")
private String swaggerScopes;
@Value("${swagger.urls}")
private String swaggerUrls; // Your v2/api-docs URL accessible from the UI
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE))
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.securitySchemes(Collections.singletonList(securitySchema()))
.securityContexts(Collections.singletonList(securityContext()));
}
private OAuth securitySchema() {
List<AuthorizationScope> authorizationScopeList = new ArrayList<>();
authorizationScopeList.add(new AuthorizationScope(swaggerScopes, ""));
List<GrantType> grantTypes = new ArrayList<>();
GrantType creGrant = new ResourceOwnerPasswordCredentialsGrant(oauthUrl + "/token");
grantTypes.add(creGrant);
return new OAuth("oauth2schema", authorizationScopeList, grantTypes);
}
private SecurityContext securityContext() {
return SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.ant(swaggerUrls)).build();
}
private List<SecurityReference> defaultAuth() {
final AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = new AuthorizationScope(swaggerScopes, "");
return Collections.singletonList(new SecurityReference("oauth2schema", authorizationScopes));
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
版本: