Learning: security login, authentication and authorization

Posted by Cheeky Chino on Sun, 02 Jan 2022 23:15:47 +0100

Set account and password

The first method: configuration file (not commonly used)
application

spring.security.user.name=admin
spring.security.user.password=123

The second method: configure the class
Need to inherit WebSecurityConfigurerAdapter

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //Password encryption
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode("456");
        //Login authentication

        auth.inMemoryAuthentication()
                .withUser("user")
                .password(encode)
                .roles("user");
    }
    @Bean
    public PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
}

Overall logic: in the security login, there are only two steps for authentication, which need programmers to do:
1. Get user information
2. Returns user information and permissions.
The rest of the authentication, judgment, etc. are completed internally by security (I don't see much about the source code, so I don't know how to complete it)
realization:
First, I need a class to return user information to security, config
Second, I need a class to get user information, service

config

@Configuration
@EnableWebSecurity
public class ConfigTest extends WebSecurityConfigurerAdapter{


    @Autowired
    private MyService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    }


    @Bean
    public PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
}

Inherit the WebSecurityConfigurerAdapter class and override the configure method. This is an empty method. The specific functions to be implemented here mainly depend on the AuthenticationManagerBuilder in parentheses. This is an authentication manager. Since it is an authentication manager, I need to give it an identity, so I lead to the userDetailsService user details, Now go to the MyService class.

@Service
public class MyService implements UserDetailsService{


    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException{
        QueryWrapper<com.tan.pojo.User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",s);
        com.tan.pojo.User user = userMapper.selectOne(wrapper);

        if(user==null){
            throw new UsernameNotFoundException("user name does not exist");
        }
        return new User(user.getUsername(),new BCryptPaswordEncoder().encode(user.getPassword()),auths);  //Simulate encryption and return the encrypted password

This is mainly used to obtain the user. You can see the first three lines in the loadUserByUsername method. mybatisPlus is used to find the relevant information of the user in the database and assign it to the user. The next step is to determine whether the user exists. If it does not exist, an exception will be reported directly. If it exists, put the current user into the AuthenticationManagerBuilder through the ConfigTest class above, and the remaining comparison operations are completed by security.

Set authentication

According to the learning needs, set which web sites can be accessed without login and which can be accessed only after login.
Rewrite the http security method in the source code

protected void configure(HttpSecurity http) throws Exception {
    this.logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
    http.authorizeRequests((requests) -> {
        ((AuthorizedUrl)requests.anyRequest()).authenticated();
    });
    http.formLogin();
    http.httpBasic();
}

Rewrite the code according to the current learning needs

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.formLogin()   //Enable custom login page
            .loginPage("/login.html") //Login page setup
            .loginProcessingUrl("/user/login").permitAll() //Login access path
            .defaultSuccessUrl("/test/index") //The default success path is the place to jump after success
            .and().csrf().disable(); //When the csrf function is turned off, security3 is turned off by default and security4 is turned on by default

    http.authorizeRequests()
            .antMatchers("/test/index").permitAll()//Give some websites a green light and you can log in without authentication
            .anyRequest().authenticated(); //All websites need to be certified
    http.formLogin();

    http.httpBasic();
}

There is a problem here. After I rewrite this method, anyrequest () in the original method authenticated(); It is invalid, so when setting the authentication login, add this sentence to the end of the authentication, otherwise an error will be reported

Error creating bean with name 'springSecurityFilterChain' defined in class path resource 
[org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: 
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; 
nested exception is java.lang.IllegalStateException: Can't configure antMatchers after anyRequest

As you can see in the last sentence, the nested exception is that ant matchers cannot be configured after anyRequest.


There is also a question I think.. Why can't you turn on the condition that all websites need authentication by default, and then write a method to close it, which makes it clearer..


There are other methods of HttpSecurity in the WebSecurityConfigurerAdapter class:

private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
    http.csrf(); //The csrf function is enabled by default
    http.addFilter(new WebAsyncManagerIntegrationFilter()); //filter
    http.exceptionHandling();  //exception handling
    http.headers(); //Safety head
    http.sessionManagement(); //Session manager
    http.securityContext();  //Store the current user account information and related permissions
    http.requestCache(); //Request cache
    http.anonymous(); //anonymous
    http.servletApi(); //Applet API
    http.apply(new DefaultLoginPageConfigurer()); //Default login page Configurator
    http.logout(); //sign out
}

3, Set authorization

There are four ways of authorization:
1,hasAuthority
realization:
Set access rights:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

Set user permissions:

http.authorizeRequests()
        .antMatchers("/test/hello").hasAnyAuthority("admin") 

Disadvantages: only one permission can be added to a user.

2,hasAnyAuthority
The upgraded version of hasAuthority solves the shortcomings of hasAuthority.
realization:
Set access rights:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

Set user permissions:

http.authorizeRequests()
        .antMatchers("/test/hello").hasAnyAuthority("admin","user") 

3,hasRole
Different from hasAuthority, you need to add a prefix: ROLE when setting access permissions_**
realization:
Set access rights:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_vvv");

Set user permissions:

http.authorizeRequests()
        .antMatchers("/test/hello").hasRole("vvv")

It should be noted here that when using hasRole, you cannot set ROLE in user permission_ Nested exceptions will be reported for permissions prefixed with.


4,hasAnyRole
It is equivalent to the combination of hasRole and hasAnyAuthority. A user can have multiple permissions, but it needs to be prefixed with ROLE when setting access permissions_**
realization:
Set access rights:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");

Set user permissions:

http.authorizeRequests()
        .antMatchers("/test/hello").hasAnyRole("admin","aaa")

Topics: Java Spring