Spring Security is one of the Security management frameworks in the Spring family. In fact, Spring Security has been developed for many years before Spring Boot, but it has not been used much.

Compared to Shiro, integrating Spring Security into SSM/SSH is a cumbersome operation, so Spring Security is more powerful than Shiro, But it’s not as useful as Shiro (although Shiro doesn’t have as many features as Spring Security, Shiro is sufficient for most projects).

Since Spring Boot has been available, Spring Boot has provided an automated configuration scheme for Spring Security that allows zero configuration of Spring Security.

So, in general, a common combination of security management technology stacks looks like this:

  • SSM + Shiro
  • Spring Boot/Spring Cloud + Spring Security

Note that this is only a recommended combination, but technically speaking, any combination will work.

Let’s see how it works.

1. Project creation

Using Spring Security in Spring Boot is very easy, just introduce dependencies:

Spring Security dependencies in POM.xml:

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

Once you add a dependency, all of the project’s interfaces are automatically protected.

2. First experience

We create a HelloController:

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(a) {
        return "hello"; }}Copy the code

To access /hello, you need to log in.

When a user sends a request to access the /hello interface from the browser, the server returns a 302 response code to redirect the client to the /login page. After the user logs in to the /login page, the client is automatically redirected to the /hello interface.

In addition, you can also use POSTMAN to send requests. When sending a request with POSTMAN, you can put the user information in the request header (to avoid redirecting to the login page) :

Spring Security supports two different authentication methods based on the above two login methods:

  • You can use the form to authenticate
  • Authentication can be done using HttpBasic

3. Configure the user name

By default, the login user name is user, and the password is a string randomly generated when the project starts. The default password can be seen in the startup console logs:

This randomly generated password changes every time you start up. There are three different ways to configure the login user name and password:

  • Configure it in application.properties
  • Configured in memory through Java code
  • Load from the database via Java

The first two are relatively simple, the third code volume is slightly large, this article will take a look at the first two, the third after a separate article to write an introduction, you can also refer to my micro personnel project.

3.1 Configuration File Configure the user name and password

You can configure basic user information directly in the application.properties file:

spring.security.user.name=javaboy
spring.security.user.password=123
Copy the code

When the configuration is complete, restart the project and you can log in using the username/password configured here.

3.2 Configuring the User Name and Password in Java

Can also configure the user name password in Java code, we first need to create a Spring Security configuration, integration since WebSecurityConfigurerAdapter class, as follows:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // The following two lines of configuration indicate that two users are configured in memory
        auth.inMemoryAuthentication()
                .withUser("javaboy").roles("admin").password("$2a$10$OR3VSksVAmCzc.7WeaRPR.t0wyCsIj24k0Bne8iKWV1o.V9wsP8Xe")
                .and()
                .withUser("lisi").roles("user").password("$2a$10$p1H8iWa8I4.CA.7Z8bwLjes91ZpY.rYREGHQEInNtAp4NzL6PLKxi");
    }
    @Bean
    PasswordEncoder passwordEncoder(a) {
        return newBCryptPasswordEncoder(); }}Copy the code

Here we configure two users in the configure method, the user password is encrypted string (plain text 123), starting from Spring5, mandatory password encryption, if you do not want to encrypt, It is possible to use NoOpPasswordEncoder, an instance of expired PasswordEncoder, but it is not recommended because it is unsafe.

Spring Security provides BCryptPasswordEncoder (BCryptPasswordEncoder), a password encoding tool, which can be very convenient to implement the password encryption and salt, the same plaintext encryption results are always different, so the user does not need to save additional salt fields, which is much more convenient than Shiro.

4. Log in and configure

For the login interface, the response after a successful login, the login response after the failure, we all can be configured in WebSecurityConfigurerAdapter implementation class. For example:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    VerifyCodeFilter verifyCodeFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);
        http
        .authorizeRequests()// Enable login configuration
        .antMatchers("/hello").hasRole("admin")// To access the /hello interface, the admin role is required
        .anyRequest().authenticated()// Represents the remaining interfaces, which can be accessed after login
        .and()
        .formLogin()
        // Define the login page. If you access an interface that can be accessed only after you have logged in, you will be automatically redirected to this page
        .loginPage("/login_p")
        // Login processing interface
        .loginProcessingUrl("/doLogin")
        // define the key of the username for login, default is username
        .usernameParameter("uname")
        // Define the key of the user password for login, default is password
        .passwordParameter("passwd")
        // Log in to the successful processor
        .successHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                    resp.setContentType("application/json; charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("success");
                    out.flush();
                }
            })
            .failureHandler(new AuthenticationFailureHandler() {
                @Override
                public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException exception) throws IOException, ServletException {
                    resp.setContentType("application/json; charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("fail");
                    out.flush();
                }
            })
            .permitAll()// All interfaces related to form logins are passed directly
            .and()
            .logout()
            .logoutUrl("/logout")
            .logoutSuccessHandler(new LogoutSuccessHandler() {
                @Override
                public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                    resp.setContentType("application/json; charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("logout success"); out.flush(); } }) .permitAll() .and() .httpBasic() .and() .csrf().disable(); }}Copy the code

In the successHandler method, you can configure a callback for a successful login. In the case of separate development, you can return JSON after a successful login. Similarly, in the failureHandler method, you can configure a callback for a failed login. In logoutSuccessHandler, a callback is configured for logging out successfully.

5. Ignore interceptions

If a request address does not need to be intercepted, there are two ways to do this:

  • Set the address for anonymous access
  • Filter the address directly, that is, the address does not go through the Spring Security filter chain

The second solution is recommended. The configuration is as follows:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/vercode"); }}Copy the code

Another powerful feature of Spring Security is that it can be used with OAuth2 to play with more tricks, which we will cover in a later article.

This article first said here, have a question welcome comment discussion.

Follow the public account [Jiangnan Little Rain], focus on Spring Boot+ micro service and the separation of the front and back end of the full stack technology, regular video tutorials to share, follow the reply to Java, get the Song brothers carefully prepared for you Java dry goods!