本篇介紹如何在Spring Boot Security設定兩個form-data的api登入,且兩個登入口驗證時的使用者來源為不同的兩個UserDetailsService
。
先參考「Spring Boot Security two form api login範例」建立專案,然後修改Spring Security設定類別DemoWebSecurityConfig
如下。
重點在各別的WebSecurityConfigurerAdapter
類別都有自己的UserDetailsService
實作,並透過各自的AuthenticationManagerBuilder
設定。
OneLoginWebSecurityConfigurerAdapter
驗證時從DemoOneUserDetailsService
查詢使用者;
TwoLoginWebSecurityConfigurerAdapter
驗證時從DemoTWoUserDetailsService
查詢使用者。
package com.abc.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
@EnableWebSecurity
public class DemoSecurityConfig {
@Configuration
@Order(1)
public static class OneLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService demoOneUserDetailsService; // inject DemoOneUserDetailsService bean
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(demoOneUserDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/one/**")
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginProcessingUrl("/one/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler( new DemoAuthenticationSuccessHandler() )
.failureHandler( new DemoAuthenticationFailureHandler() )
.and()
.exceptionHandling()
.authenticationEntryPoint(new DemoAuthenticationEntryPoint())
.and()
.csrf()
.disable();
}
}
@Configuration
@Order(2)
public static class TwoLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService demoTwoUserDetailsService; // inject DemoTwoUserDetailsService bean
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(demoTwoUserDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/two/**")
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginProcessingUrl("/two/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler( new DemoAuthenticationSuccessHandler() )
.failureHandler( new DemoAuthenticationFailureHandler() )
.and()
.exceptionHandling()
.authenticationEntryPoint(new DemoAuthenticationEntryPoint())
.and()
.csrf()
.disable();
}
}
}
接著建立兩個UserDetailsService
的實作,
DemoOneUserDetailsService
及DemoTwoUserDetailsService
。
DemoOneUserDetailsService
的使用者為帳密為one123/one123
。
DemoOneUserDetailsService
package com.abc.demo.config;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class DemoOneUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
return User.withUsername("one123")
.password("{noop}one123")
.roles("USER")
.build();
}
}
DemoTwoUserDetailsService
的使用者為帳密為two123/two123
。
DemoTwoUserDetailsService
package com.abc.demo.config;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class DemoTwoUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
return User.withUsername("two123")
.password("{noop}two123")
.roles("USER")
.build();
}
}
完成全部設定後的專案目錄結構如下
開啟Postman來進行登入測試。
在Postman輸入POST
|http://localhost:8080/demo/one/login
並夾帶下面username/password從登入點一登入
KEY | VALUE |
---|---|
username | one123 |
password | one123 |
在Postman輸入POST
|http://localhost:8080/demo/two/login
並夾帶下面username/password從登入點二登入
KEY | VALUE |
---|---|
username | two123 |
password | two123 |
登入配置一的使用者帳密無法通過登入配置二的驗證,反之亦然。
也就是說,
能通過登入口一驗證的使用者僅限於DemoOneUserDetailsService
的使用者。
能通過登入口二驗證的使用者僅限於DemoTwoUserDetailsService
的使用者。
不過一旦通過驗證並成功登入,不論是從哪個登入點登入都可以存取另一個登入配置所保護的路徑資源。
例如成功登入POST
|http://localhost:8080/demo/one/login
的使用者也可存取
POST
|http://localhost:8080/demo/two/resource
的資源。
參考:
沒有留言:
張貼留言