我将此代码用于Rest API身份验证:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Optional<String> basicToken = Optional.ofNullable(request.getHeader(HttpHeaders.AUTHORIZATION))
.filter(v -> v.startsWith("Basic"))
.map(v -> v.split("\\s+")).filter(a -> a.length == 2).map(a -> a[1]);
if (!basicToken.isPresent()) {
return sendAuthError(response);
}
byte[] bytes = Base64Utils.decodeFromString(basicToken.get());
String namePassword = new String(bytes, StandardCharsets.UTF_8);
int i = namePassword.indexOf(':');
if (i < 0) {
return sendAuthError(response);
}
String name = namePassword.substring(0, i);
String password = namePassword.substring(i + 1);
// Optional<String> clientId = authenticationService.authenticate(name, password, request.getRemoteAddr());
Merchants merchant = authenticationService.authenticateMerchant(name, password, request.getRemoteAddr());
if (merchant == null) {
return sendAuthError(response);
}
request.setAttribute(CURRENT_CLIENT_ID_ATTRIBUTE, merchant.getId());
return true;
}
我如何使用Spring Security重写代码以获得相同的结果,但使不同的链接具有身份验证?例如:
localhost:8080/v1/notification - requests should NOT be authenticated.
localhost:8080/v1/request - requests should be authenticated.
答案 0 :(得分:3)
在这里您可以找到一个有效的项目https://github.com/angeloimm/springbasicauth
我知道pom.xml文件中有很多无用的依赖关系,但是我从一个已经存在的项目开始,而且我没有时间去纯化它
基本上,您必须:
让我解释一下代码。
Spring MVC配置:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {"it.olegna.test.basic"})
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
}
这里,我们没有做任何其他事情来配置Spring MVC,方法是告诉它在哪里可以找到控制器等,并使用单个消息转换器。 MappingJackson2HttpMessageConverter
以产生JSON响应
Spring Security配置:
@Configuration
@EnableWebSecurity
@Import(value= {WebMvcConfig.class})
public class WebSecConfig extends WebSecurityConfigurerAdapter {
@Autowired private RestAuthEntryPoint authenticationEntryPoint;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("test")
.password(passwordEncoder().encode("testpwd"))
.authorities("ROLE_USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/securityNone")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
在这里,我们配置Spring Security以便对除以securityNone开头的所有请求使用HTTP基本认证。我们使用NoOpPasswordEncoder
来编码提供的密码;这个PasswrodEncoder绝对不做任何事情……它保持原样。
RestEntryPoint :
@Component
public class RestAuthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
此入口点将禁用所有不包含 Authentication 标头
的请求SimpleDto :非常简单的DTO,代表控制器的JSON答案
public class SimpleDto implements Serializable {
private static final long serialVersionUID = 1616554176392794288L;
private String simpleDtoName;
public SimpleDto() {
super();
}
public SimpleDto(String simpleDtoName) {
super();
this.simpleDtoName = simpleDtoName;
}
public String getSimpleDtoName() {
return simpleDtoName;
}
public void setSimpleDtoName(String simpleDtoName) {
this.simpleDtoName = simpleDtoName;
}
}
TestBasicController :一个非常简单的控制器
@RestController
@RequestMapping(value= {"/rest"})
public class TestBasicController {
@RequestMapping(value= {"/simple"}, method= {RequestMethod.GET}, produces= {MediaType.APPLICATION_JSON_UTF8_VALUE})
public ResponseEntity<List<SimpleDto>> getSimpleAnswer()
{
List<SimpleDto> payload = new ArrayList<>();
for(int i= 0; i < 5; i++)
{
payload.add(new SimpleDto(UUID.randomUUID().toString()));
}
return ResponseEntity.ok().body(payload);
}
}
因此,如果您使用邮递员或任何其他测试人员尝试此项目,则可能有两种情况:
让我们假设您要调用URL http://localhost:8080/test_basic/rest/simple而不传递Authentication标头。 HTTP状态代码将为401 Unauthorized
这意味着需要身份验证标头
通过将此标头添加到请求Authorization Basic dGVzdDp0ZXN0cHdk
中,效果很好
请注意,字符串dGVzdDp0ZXN0cHdk
是字符串username:password
的Base64编码。在我们的例子中,是inMemoryAuthentication中定义的test:testpwd
的Base64编码
我希望这是有用的
天使
网络安全用户数据服务
为了配置Spring安全性以从DB检索用户详细信息,您必须执行以下操作:
创建像这样的org.springframework.security.core.userdetails.UserDetailsService实现:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private BasicService svc;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
BasicUser result = svc.findByUsername(username);
if( result == null )
{
throw new UsernameNotFoundException("No user found with username "+username);
}
return result;
}
}
将其注入spring安全配置并按如下方式使用它:
public class WebSecConfig extends WebSecurityConfigurerAdapter {
@Autowired private RestAuthEntryPoint authenticationEntryPoint;
@Autowired
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// auth
// .inMemoryAuthentication()
// .withUser("test")
// .password(passwordEncoder().encode("testpwd"))
// .authorities("ROLE_USER");
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/securityNone")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
我在我提供的github链接上推送了代码。在那里,您可以找到基于以下内容的完整示例:
随时根据自己的情况进行调整
答案 1 :(得分:1)
您可以使用baeldung.com或mkyong.com之类的各种网站上描述的默认spring-security配置。您的示例中的技巧似乎是调用Merchant
的方法。根据{{1}}和authenticationService
对象的复杂程度,您可以使用以下代码,也可以实现外观以实现类似的行为。
Merchant
在请求上设置属性,必要时可以通过单独的过滤器完成,该过滤器将@Autowired
public void authenticationManager(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(new AuthenticationProvider() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Merchants merchant = authenticationService.authenticateMerchant(name, password, request.getRemoteAddr());
if(merchant == null) {
throw new AuthenticationException("No Merchant found.");
}
return new UsernamePasswordAuthenticationToken(name, password, merchant.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
});
}
中的Principal
作为属性放入请求中。