Somehow, I wrote it in a style for SIer. The environment is also Java 1.7.
The method of Basic authentication in Spring Boot is explained using sample code. Assuming the usage scene as WebAPI, the setting is set to support stateless communication.
Version | |
---|---|
Java | 1.7 |
Spring Boot | 1.5.9.RELEASE |
Make the following settings in JavaConfig. Refer to the comments in the source code for specific settings.
--Spring Security settings --Basic authentication --Settings for stateless communication --Bean definition - userDetailsService - passwordEncoder
MyConfigure.java
@Configuration
public class MyConfigure extends WebSecurityConfigurerAdapter {
// ----------------------------------------
//Spring Security settings
// ----------------------------------------
// <<<* Please note that WebSecurityConfigurerAdapter has multiple configure overload methods.>>>
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { super.configure(auth); }
@Override public void configure(WebSecurity web) throws Exception { super.configure(web); }
//---
@Override
protected void configure(HttpSecurity http) throws Exception {
//Basic authentication settings
http.httpBasic().realmName("My sample realm");
//Setting requests that require authentication
http.authorizeRequests().anyRequest().authenticated();
//If CSRF measures are enabled, POST without Token will result in an error, so disable it.
http.csrf().disable();
//Authentication information is always obtained from the Authorization header, so session management using cookies is not required.
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
// ----------------------------------------
//Bean definition
// ----------------------------------------
@Bean
public UserDetailsService userDetailsService() {
return new LoginPrincipal.LoginPrincipalService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Credentials are defined as a class that implements ʻUserDetails [^ fqdn-1](
LoginPrincipal`).
This class should be designed with the following points in mind.
--Keep only the information required for authentication --Define "user" information required for business separately from this class --Clarify the meaning of * username * in ʻUserDetails`
Based on the above, this sample has the following design.
-Hold "Login ID" in * username * --Hold "employee number" in addition to ʻUserDetails` information
ʻBy defining the implementation class of UserDetailsService [^ fqdn-2] as a bean, you can define the implementation when Spring Security searches for credentials (
LoginPrincipal.LoginPrincipalService). This class is defined as an inner class of
LoginPrincipal` for code simplification.
In the LoginPrincipal.DB
class, dummy processing is defined to enable the sample code to operate alone.
LoginPrincipal.java
// ======================================================================
//* UserDetails implementation class
// ======================================================================
public class LoginPrincipal extends org.springframework.security.core.userdetails.User {
// ※loginId(Login ID)Is super.Keep in username
private final String employeeNumber; //employee number
public LoginPrincipal(String loginId, String employeeNumber, String encodedPassword, String[] roles) {
super(loginId, encodedPassword, true, true, true, true, AuthorityUtils.createAuthorityList(roles));
this.employeeNumber = employeeNumber;
}
public String getLoginId() {
return super.getUsername();
}
// <<< Getter >>>
public String getEmployeeNumber() { return this.employeeNumber; }
//---
// ======================================================================
//* Implementation class of UserDetailsService
// ======================================================================
public static class LoginPrincipalService implements org.springframework.security.core.userdetails.UserDetailsService {
/**
*Search for credentials with the specified login ID.
*If no credentials are found, the result is{@code null}is.
*/
public LoginPrincipal findByLoginId(String loginId) {
//* Actually, the authentication information is obtained from the DB here.
return DB.AUTH_TABLE.get(loginId);
}
/** {@inheritDoc} */
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//* For username, the "user name" for basic authentication is set by the authentication function of Spring Security.
//Delegated to findByLoginId
LoginPrincipal found = this.findByLoginId(username);
if (found == null) {
throw new UsernameNotFoundException("username not found: " + username);
}
return found;
}
}
// ======================================================================
// (For samples)Hold user authentication information in Map as an alternative to user authentication master
// ======================================================================
private static class DB {
public static final Map<String, LoginPrincipal> AUTH_TABLE = new HashMap<>();
static {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
LoginPrincipal[] data = { //
new LoginPrincipal("U001", "S000001", passwordEncoder.encode("pass1"), new String[] { "USER" }), //
new LoginPrincipal("U002", "S000002", passwordEncoder.encode("pass2"), new String[] { "USER" }), //
};
for (LoginPrincipal d : data) {
AUTH_TABLE.put(d.getLoginId(), d);
}
}
}
}
Basic authentication is now enabled. The following is a sample that refers to the authentication information from the Controller.
MyController.java
@RestController
public class MyController {
@GetMapping
public String index() {
SecurityContext securityContext = SecurityContextHolder.getContext();
LoginPrincipal loginPrincipal = (LoginPrincipal) securityContext.getAuthentication().getPrincipal();
return "Hello " + loginPrincipal.getEmployeeNumber() + "!";
}
}
This is my first Qiita post. I hope I can continue. Thank you for your guidance and encouragement.
Recommended Posts