问题描述:
最近公司想开发官网,之前的项目使用oauth2,所有接口都需要登录认证。官网接口空顶无法登录后再调取,所以想开放某些接口用于首页直接使用。
解决方案:
之前的解决方案是在ResourceServerConfig类中configure方法中对部分接口开放,
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore jwtTokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resource) throws Exception {
resource.resourceId("app").tokenStore(jwtTokenStore);
OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
authenticationEntryPoint.setExceptionTranslator(new CustomExceptionTranslator());
resource.authenticationEntryPoint(authenticationEntryPoint);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/file/**").permitAll().and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
之前关键是在这行代码authorizeRequests().antMatchers("/file/**").permitAll(),在antMatchers中添加要开放的接口地址。之前使用shiro,可以通过注解方式自定义控制接口无需认证访问的解决,我这次也想这样做。
1.先定义一个注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthIgnore {
boolean required() default true;
}
2.编写配置类
@Configurable
@Component
@ConfigurationProperties(prefix = "security.oauth2.client.ignore-urls")
public class AuthIgnoreConfig implements InitializingBean {
@Autowired
private WebApplicationContext applicationContext;
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
private static final String ASTERISK = "*";
@Getter
@Setter
private List<String> ignoreUrls = new ArrayList<>();
@Override
public void afterPropertiesSet() throws Exception {
RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
map.keySet().forEach(mappingInfo -> {
HandlerMethod handlerMethod = map.get(mappingInfo);
AuthIgnore method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), AuthIgnore.class);
Optional.ofNullable(method)
.ifPresent(authIgnore -> mappingInfo
.getPatternsCondition()
.getPatterns()
.forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, ASTERISK))));
AuthIgnore controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), AuthIgnore.class);
Optional.ofNullable(controller)
.ifPresent(authIgnore -> mappingInfo
.getPatternsCondition()
.getPatterns()
.forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, ASTERISK))));
});
}
}
3.简单修改ResourceServerConfig类
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore jwtTokenStore;
private final AuthIgnoreConfig authIgnoreConfig;
public ResourceServerConfig(AuthIgnoreConfig authIgnoreConfig) {
this.authIgnoreConfig = authIgnoreConfig;
}
@Override
public void configure(ResourceServerSecurityConfigurer resource) throws Exception {
resource.resourceId("app").tokenStore(jwtTokenStore);
OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
authenticationEntryPoint.setExceptionTranslator(new CustomExceptionTranslator());
resource.authenticationEntryPoint(authenticationEntryPoint);
}
@Override
public void configure(HttpSecurity http) throws Exception {
String[] urls = authIgnoreConfig.getIgnoreUrls().stream().distinct().toArray(String[]::new);
http
.csrf().disable()
.authorizeRequests().antMatchers("/file/**").permitAll()
.and().authorizeRequests().antMatchers(urls).permitAll()
.and()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
4.在方法Controller或者接口上添加注解@AuthIgnore即可实现