spring-security(十四)UserDetailsService

Foreword:
  As the core class of spring security, most authentication methods use the two interfaces UserDetailsService and UserDetails. This article will discuss UserDetailsService and its implementation classes in detail.

1. UserDetailsService interface
In spring security, in order to facilitate expansion, the UserDetailsService interface is designed to be extremely simple and contains only one method
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

According to the provided username, look up the corresponding user information, just look up the information, there is no logic related to authentication, it is the user information used by DaoAuthenticationProvider by default and added to the class, and the returned UserDetails is also an interface. Depending on the specific implementation, the user information search may be case-sensitive or insensitive, so the user name in UserDetails may not necessarily be the same as the incoming user name. In some authentication methods, even if they do not really use the user name and password, the UserDetailsService class will be used, and they may just want to use the GrantedAuthority information in the UserDetails object to make permission judgments (such as LDAP, X.509, CAS, etc., These authentication systems themselves take on the task of verifying that the certificate is valid).
Because the UserDetailsService interface is so simple, we can easily implement it to customize our logic for obtaining user information, and spring security also provides us with some basic common implementations.
2. Memory-based authentication
It is not troublesome for a custom UserDetailsService to obtain data from a data persistence engine (file, database, etc.) we like, but sometimes we don't need such a complicated implementation, for example, we just do a The prototype of spring security, or if you are learning spring security, you don't want to spend time building a database. At this time, you can use memory-based user information storage. Use java config to configure user information as follows:
	@Bean
	public UserDetailsService userDetailsService() {
		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
		manager.createUser(User.withUsername("user").password("password").roles("USER").build());
		manager.createUser(User.withUsername("admin").password("password").roles("ADMIN").build());
		return manager;
	}

This way also supports properties file to configure
@Bean
	public UserDetailsService userDetailsService() throws FileNotFoundException, IOException {

		Properties properties = new Properties();
		properties.load(getClass().getClassLoader().getResourceAsStream("users.properties"));

		return new InMemoryUserDetailsManager(properties);
	}

The file format of properties is as follows:
username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]

E.g
 
jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
bob=bobspassword,ROLE_USER,enabled

You can also use the following code snippet to create
@Autowired
	public void auth(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication()
				.withUser("admin").password("password").authorities("ROLE_ADMIN").and()
				.withUser("user").password("password").authorities("ROLE_USER");
	}

3. Authentication based on relational database
3.1 spring security also provides us with an implementation of obtaining authentication information from relational database - JdbcDaoImpl, which uses Spring JDBC inside this class. The following is a specific configuration example.
@Bean
	public DruidDataSource dataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUsername("root");
		dataSource.setPassword("sso");
		dataSource.setName("chengf");
		dataSource.setUrl("jdbc:mysql://localhost:3306/chengf?useUnicode=true&characterEncoding=UTF-8");
		dataSource.setMaxActive(20);
		dataSource.setInitialSize(1);
		dataSource.setMaxWait(60000);
		dataSource.setMinIdle(1);
		dataSource.setTimeBetweenEvictionRunsMillis(60000);
		dataSource.setMinEvictableIdleTimeMillis(300000);
		dataSource.setValidationQuery("select 'x'");
		dataSource.setPoolPreparedStatements(true);
		dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
		return dataSource;
	}

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
		auth.jdbcAuthentication().dataSource(dataSource);
	}

For a complete example, please refer to spring-security (4) jdbc 3.2 of java config-sample
By default, JdbcDaoImpl directly obtains the permission list information corresponding to a specific user from the database. In practical applications, we may first group users. Then assign specific permissions to a group, so that users in this group have these permissions. JdbcDaoImpl also provides us with grouping support, which is not enabled by default. If you want to use this function, you can set it as follows
@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
		auth.jdbcAuthentication().dataSource(dataSource).getUserDetailsService().setEnableGroups(true);;
	}

If spring's default schema cannot meet our business requirements (the definition of table structure, the integrity of information), we can also use JdbcDaoImpl to rewrite the query statement. For example, if we want to rewrite the statement to query user information, it can be configured as follows
@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
		auth.jdbcAuthentication().dataSource(dataSource).getUserDetailsService().setEnableGroups(true);;
		auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("select username,password,email,phone,address,enabled from my_user_table where username = ? ");
	}

If the default implementation is too different from our needs, and simply modifying the configuration can no longer meet our needs, we can implement the class for loading user information by ourselves, that is, implement UserDetailsService and register it in spring as a bean.

@Bean
	public DruidDataSource dataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUsername("root");
		dataSource.setPassword("sso");
		dataSource.setName("chengf");
		dataSource.setUrl("jdbc:mysql://localhost:3306/chengf?useUnicode=true&characterEncoding=UTF-8");
		dataSource.setMaxActive(20);
		return dataSource;
	}
	@Bean
	public UserDetailsService userDetailsService () {
		MyUserDetailsService userDetailsService = new MyUserDetailsService();
		userDetailsService.setDataSource(dataSource());
		return userDetailsService;
	}

In this way, when the program starts, when the configuration class InitializeUserDetailsManagerConfigurer is loaded, a DaoAuthenticationProvider will be created for us, and the UserDetailsService we defined will be used. For the specific process, please refer to
spring-security (2) java config loading mechanism - @EnableGlobalAuthentication

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326077983&siteId=291194637