Use SpringSecurity saver security

First, the introduction of dependence:

<dependency>    
    <groupId>org.springframework.boot</groupId>    
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

After the introduction of this dependency, your web application will have the following features:

  • All requests require certification path
  • No specific roles and permissions
  • No login page, using HTTP Basic authentication
  • Only one user name for the user


Configuration SpringSecurity

springsecurity configuration item, is preferably stored in a separate configuration classes:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
}



Configuring user authentication

First of all, to solve is user registration, storing user information. springsecurity offers four stores the user's way:

  • Memory-based (production certainly does not use)
  • Based on JDBC
  • Based on LDAP
  • User-defined (most common)

Using any of a manner to cover the need configure(AuthenticationManagerBuilder auth)methods:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    }
}

1. Based on Memory

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("zhangsan").password("123").authorities("ROLE_USER")
            .and()
            .withUser("lisi").password("456").authorities("ROLE_USER");
}

2. Based on JDBC

@Autowired
DataSource dataSource;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication()
        .dataSource(dataSource);
}

JDBC-based way, you must have some specific exemplar, and field meet its query rules:

public static final String DEF_USERS_BY_USERNAME_QUERY =
    "select username,password,enabled " +
    "from users " +
    "where username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
    "select username,authority " +
    "from authorities " +
    "where username = ?";
public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY = 
    "select g.id, g.group_name, ga.authority " +
    "from groups g, group_members gm, group_authorities ga " +
    "where gm.username = ? " +
    "and g.id = ga.group_id " +
    "and g.id = gm.group_id";

Of course, you can modify these statements about:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
    auth.jdbcAuthentication().dataSource(dataSource)
        .usersByUsernameQuery("select username, password, enabled from Users " +
                              "where username=?")
        .authoritiesByUsernameQuery("select username, authority from UserAuthorities " +
                                    "where username=?");

There is a problem, your database password encryption may be a way encrypted, and the user is transmitted in plain text, more time needs to be encrypted, springsecurity also provides a corresponding function:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
    auth.jdbcAuthentication().dataSource(dataSource)
        .usersByUsernameQuery("select username, password, enabled from Users " +
                              "where username=?")
        .authoritiesByUsernameQuery("select username, authority from UserAuthorities " +
                                    "where username=?")
        .passwordEncoder(new StandardPasswordEncoder("53cr3t");

passwordEncoderThe method of delivery is the PasswordEncoderimplementation of the interface, which provides a number of default to achieve, if not satisfied, you can implement this interface:

  • BCryptPasswordEncoder

  • NoOpPasswordEncoder
  • Pbkdf2PasswordEncoder
  • Shcryptfssvordetrrchoder
  • StandardPasswordEncoder(SHA-256)

3. Based on LDAP

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.ldapAuthentication()
        .userSearchBase("ou=people")
        .userSearchFilter("(uid={0})")
        .groupSearchBase("ou=groups")
        .groupSearchFilter("member={0}")
        .passwordCompare()
        .passwordEncoder(new BCryptPasswordEncoder())
        .passwordAttribute("passcode")
        .contextSource()
            .root("dc=tacocloud,dc=com")
            .ldif("classpath:users.ldif");

4. User-defined method (most commonly used)

First, you need a user entity class that implements UserDetailsthe interface, the interface to achieve this is to provide more information to the frame, you can see it as Entity Framework classes used:

@Data
public class User implements UserDetails {

    private Long id;
    private String username;
    private String password;
    private String fullname;
    private String city;
    private String phoneNumber;
    
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }
}

With entity class, you also need Service logic layer, springsecurity provides UserDetailsServiceinterfaces, see the name to know Italian, you just by loadUserByUsernamereturning a UserDetailstarget to become, whether it is file-based, database, or based on LDAP, the rest pay a comparative judgment framework completed:

@Service
public class UserService implements UserDetailsService {
    
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return null;
    }
    
}

Finally, the application:

@Autowired
private UserDetailsService userDetailsService;

@Bean
public PasswordEncoder encoder() {
    return new StandardPasswordEncoder("53cr3t");
}

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



Configuration certification path

Know how to authenticate, but now there are several issues, such as user login page does not need certification, it can be used configure(HttpSecurity http)to configure the authentication path:

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

You can use this method, the following functions:

  • Before providing the interface service, the request must meet certain conditions determined
  • Configuring the login page
  • It allows the user to log out
  • Cross-site request forgery protection

1. Protection Request

@Override
protected void configure(HttpSecurity http) throws Exception {  
    http.authorizeRequests()
        .antMatchers("/design", "/orders").hasRole("ROLE_USER")
        .antMatchers(“/”, "/**").permitAll();
}

Pay attention to the order, in addition to hasRole and permitAll there are other access authentication methods:

method effect
access(String) If given the results SpEL expression is true, allows access
anonymous() Allow access to anonymous users
authenticated() It allows users to access authenticated
denyAll () Unconditional Access Denied
fullyAuthenticated() If the user is fully authenticated, access is granted
hasAnyAuthority (String ...) If any user has given permission, allow access
hasAnyRole (String ...) If the user has any given role, it allows access
hasAuthority(String) If the user has given permission, allow access
hasIpAddress(String) If a request from a given IP address, access is granted
hasRole(String) If the user has given role is allowed access
not() Negative affect any other access method
permitAll () Allow unconditional access
rememberMe() Allows users to access authenticated by remember-me

Most methods for the preparation of a specific embodiment, but access(String)may be used SpEL into some special settings, but also a large part of the same method as above:

expression effect
authentication User authentication objects
denyAll Always evaluate to false
hasAnyRole(list of roles) If the user has any given role, that is true
hasRole(role) If the user has given role (true)
hasIpAddress(IP address) If the request from a given IP address that is true
isAnonymous() If the user is an anonymous user (true)
isAuthenticated() If the user is authenticated, that is true
isFullyAuthenticated() If the user is fully authenticated, for the true (not authenticated by remember-me)
isRememberMe() If the user is authenticated by remember-me, that is true
permitAll Always evaluate to true
principal The main target users

Example:

@Override
protected void configure(HttpSecurity http) throws Exception {  
    http.authorizeRequests()
        .antMatchers("/design", "/orders").access("hasRole('ROLE_USER')")
        .antMatchers(“/”, "/**").access("permitAll");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/design", "/orders").access("hasRole('ROLE_USER') && " +
         "T(java.util.Calendar).getInstance().get("+"T(java.util.Calendar).DAY_OF_WEEK) == " +          "T(java.util.Calendar).TUESDAY")
        .antMatchers(“/”, "/**").access("permitAll");
}

2. Configure the login page

@Override
protected void configure(HttpSecurity http) throws Exception {  
    http.authorizeRequests()
        .antMatchers("/design", "/orders").access("hasRole('ROLE_USER')")
        .antMatchers(“/”, "/**").access("permitAll")
        .and()
        .formLogin()
            .loginPage("/login");
}

// 增加视图处理器
@Overridepublic void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("home"); 
    registry.addViewController("/login");
}

By default, I want to pass a username and password , but you can change:

.and()
    .formLogin()
        .loginPage("/login")
        .loginProcessingUrl("/authenticate")
        .usernameParameter("user")
        .passwordParameter("pwd")

You can also modify the default login success page:

.and()
    .formLogin()
        .loginPage("/login")
        .defaultSuccessUrl("/design")

3. Configure logout

.and()
    .logout()
         .logoutSuccessUrl("/")

4.csrf attack

springsecurity enabled by default to prevent csrf attack, you only need to add at the time of delivery:

<input type="hidden" name="_csrf" th:value="${_csrf.token}"/>

Of course, you can also turn off, but this is not recommended:

.and()
    .csrf()
        .disable()


You know who the user is

Only control user login and sometimes is not enough, you may also want to obtain user information has been registered in the rest of the program, there are several ways to do this:

  • The Principal Object injection control method

  • The Authentication target injection control method
  • Use SecurityContextHolder get the security context
  • Use @AuthenticationPrincipal annotation method

1. Principal Object injection control method

@PostMappingpublic String processOrder(@Valid Order order, Errors errors,SessionStatus sessionStatus,Principal principal) {
    ...  
    User user = userRepository.findByUsername(principal.getName());
    order.setUser(user);
    ...
}

2. Authentication target injection control method

@PostMappingpublic String processOrder(@Valid Order order, Errors errors, SessionStatus sessionStatus, Authentication authentication) {
    ...
    User user = (User) authentication.getPrincipal();
    order.setUser(user);
    ...
}

3. Use SecurityContextHolder get the security context

Authentication authentication =
    SecurityContextHolder.getContext().getAuthentication();
    User user = (User) authentication.getPrincipal();

4. @AuthenticationPrincipal annotation method

@PostMappingpublic String processOrder(@Valid Order order, Errors errors,SessionStatus sessionStatus, @AuthenticationPrincipal User user) {
    if (errors.hasErrors()) {
        return "orderForm";  
    }  
    order.setUser(user);
    orderRepo.save(order);
    sessionStatus.setComplete();
    return "redirect:/";
}

Guess you like

Origin www.cnblogs.com/NameZZH/p/11457146.html