[英]Implement Spring Security for Rest Api
我將以下代碼用於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.
在這里您可以找到一個有效的項目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響應
春季安全配置 :
@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");
}
}
該入口點禁用所有不包含身份驗證標頭的請求
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編碼; 在我們的例子中,是test:testpwd
定義的test:testpwd
的Base64編碼
我希望這是有用的
安傑洛
網絡安全用戶數據服務
為了配置Spring安全性以從數據庫檢索用戶詳細信息,您必須執行以下操作:
創建一個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鏈接上推送了代碼。 在那里,您可以找到基於以下內容的完整工作示例:
隨時根據自己的情況進行調整
您可以使用在baeldung.com或mkyong.com等各種網站上描述的默認spring-security配置。 您的示例中的技巧似乎是致電來獲取Merchant
。 根據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));
}
});
}
如果需要,可以通過一個單獨的過濾器在請求上設置屬性,該過濾器將從SecurityContext
獲取Principal
並將其作為屬性放入請求中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.