Springboot integrates springsecurity II

Prodigal son Tang Shao 2022-02-13 07:29:59 阅读数:81

springboot integrates springsecurity ii

SpringBoot Integrate SpringSecurity Two

In the previous chapter Introductory cases in , We implemented the entry program , In this chapter, we complete the automatic login function and exception handling on the basis of the previous chapter .

Source code address of this case :https://gitee.com/lin8081/LWH11

1. automatic logon

The so-called first visit to the website is automatic , Enter your username and password , Then check the auto login check box , After entering the home page , Click exit to log in , Close page , Open the same website again , There is no need to enter the account and password again , Go straight to the home page , This interaction is “ automatic logon ”.

1. Modify the login page :login.html

<form method="post" action="/login">
<!-- account number -->
<div class="layui-form-item">
<label class="layui-form-label"> account number </label>
<div class="layui-input-block">
<input name="username" id="userName" value="admin" placeholder=" Default account :admin" type="text" lay-verify="required" class="layui-input">
</div>
</div>
<!-- password -->
<div class="layui-form-item">
<label class="layui-form-label"> password </label>
<div class="layui-input-block">
<input name="password" id="password" value="123" placeholder=" Default password :123" type="password" lay-verify="required" class="layui-input">
</div>
</div>
<!-- automatic logon -->
<div class="layui-form-item">
<label><input style="display: inline" type="checkbox" name="remember-me"/> automatic logon </label>
</div>
<div>
<button type="submit" class="layui-btn layui-btn-fluid" > deng record </button>
</div>
</form>

2. Implementation of automatic login — Database storage

Use Cookie Although storage is convenient , however Cookie After all, it's saved on the client , and Cookie The value of is also associated with the user name 、 The password is related to these sensitive information , Although it's encrypted , But store this sensitive information on the client , After all, it's not very safe .

**SpringSecurity It also provides another relatively safe implementation mechanism : **

  • On the client side Cookie in , Save only one meaningless encryption string ( It has nothing to do with sensitive information such as user name and password ), Then save the encryption string in the database - Corresponding relationship of user information , When logging in automatically , use Cookie Encryption string in , Go to the database to verify , If you pass , Automatic login is successful .

1. The basic principle

When the browser initiates a form login request , When passed UsernamePasswordAuthenticationFilter After successful certification , Pass by RememberMeService, One of them TokenRepository , It's going to generate one token, First of all, will token Write to browser Cookie in , And then token、 The user name with successful authentication is written to the database .

When the browser next requests , Pass by RememberMeAuthenticationFilter, It reads Cookie Medium token, hand RememberMeService , Get user information , And put the user information into SpringSecurity in , Automatic login .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-lk1OUSjB-1584085522201)(assets/1583765716646.png)]

RememberMeAuthenticationFilter It is a relatively backward position in the whole filter chain , In other words, automatic login will only be used when the traditional login methods are unable to log in .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-S4TsyYmA-1584085522204)(assets/1583765815108.png)]

3. establish token Database table

It can be created by the following code token surface , But the database table already exists , Please comment out , Otherwise, an error will be reported

tokenRepository.setCreateTableOnStartup(true);

It can also be direct sql Statement to create a table structure

CREATE TABLE `persistent_logins` (
`username` varchar(64) NOT NULL,
`series` varchar(64) NOT NULL,
`token` varchar(64) NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

4. Code implementation

stay WebSecurityConfig In the injection dataSource , Create a PersistentTokenRepository Of Bean object :

@Autowired
private DataSource dataSource;
@Bean
public PersistentTokenRepository persistentTokenRepository() {

JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
// If token Table does not exist , Use the following to automatically initialize the table structure , If it already exists , Please comment out , Otherwise, an error will be reported 
// tokenRepository.setCreateTableOnStartup(true);
return tokenRepository;
}

stay config() Configure automatic login in :

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

http.authorizeRequests()
// If there is one that allows anonymity url, Fill it in below 
// .antMatchers().permitAll()
.anyRequest().authenticated()
.and()
// Set landing page 
.formLogin().loginPage("/login")
// Set login success page 
.defaultSuccessUrl("/").permitAll()
// Customize login user name and password parameters , The default is username and password
// .usernameParameter("username")
// .passwordParameter("password")
.and()
.logout().permitAll()
// automatic logon 
.and().rememberMe()
.tokenRepository(persistentTokenRepository())
// token Valid time , Company :s
.tokenValiditySeconds(60)
.userDetailsService(userDetailsService);
// close CSRF Cross domain 
http.csrf().disable();
}

3. Run the test

Check auto login ,Cookie And database token Information :

 Insert picture description here

2. exception handling

When our login fails ,SpringSecurity Helped us jump to /login?error URL, Strangely, there is no error message printed on either the console or the web page .

This is because first of all /login?error yes SpringSecurity Default failure URL, Second, if you don't handle this exception yourself , This exception will not be handled .

1. Common abnormal

Let's first list some SpringSecurity Common exceptions in :

  • UsernameNotFoundException ( The user doesn't exist )
  • DisableException( User disabled )
  • BadCredentialsException( Bad credentials )
  • LockedException( Account lock )
  • CerdentialsExpiredException( Certificate expired )
  • … The exceptions listed above are AuthenticationException Subclasses of , Then let's see SpringSecurity How to deal with AuthenticationException Anomalous .

2. Source code analysis

SpringSecurity The exception handling of is carried out in the filter , We are AbastrctAuthenticationProcessingFilter Found a pair of Authentication To deal with :

  • stay doFilter() in , Capture AuthenticationException abnormal , And to unsuccessfulAuthentication() Handle .

  • stay unsuccessfulAuthentication() in , It was handed over to SimpleUrlAuthenticationFailureHandler Class onAuthencicationFailure() Handle .

  • stay onAuthenticationFailure() in , First, judge whether there is a setting defaultFailureUrl.

    a. If not set , Go straight back to 401 error , namely HttpStatus.UNAUTHORIZED Value . b. If set , First, execute saveException() Method . And then determine forwardToDestination Whether to adjust for the server , Redirection is used by default, that is, the client jumps .

  • stay saveException() In the method , First judgement forwardToDestination, If server jump is used, write Request, When the client jumps, it writes Session. Write a file named WebAttributes.AUTHENTICATION_EXCEPTION Constant corresponds to the value SPRING_SECURITY_LAST_EXCEPTION, The value is AuthenticationException object .

  • thus SpringSecurity Completed exception handling , Summarize the process :

    –> AbstractAuthenticationProcessingFilter.doFilter() –> AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication() –> SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure() –> SimpleUrlAuthenticationFailureHandler.saveException()

3. Handling exceptions

It looks very complicated through the source code , But it's really handled SpringSecurity It provides us with a convenient way , We just need to specify the wrong url, Then handle the exception in this method .

  • Designation error url , stay WebSecurityConfig Add .failureUrl("/login/error")
@Override
protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()
// If there is one that allows anonymity url, Fill it in below 
// .antMatchers().permitAll()
.anyRequest().authenticated()
.and()
// Set landing page 
.formLogin().loginPage("/login")
// Setting login succeeded url
.defaultSuccessUrl("/").permitAll()
// Failed to set login url
.failureUrl("/login/error")
// Customize login user name and password parameters , The default is username and password
// .usernameParameter("username")
// .passwordParameter("password")
.and()
.logout().permitAll()
// automatic logon 
.and().rememberMe()
.tokenRepository(persistentTokenRepository())
// Valid time , Company :s
.tokenValiditySeconds(60)
.userDetailsService(userDetailsService);
// close CSRF Cross domain 
http.csrf().disable();
}
  • stay Controller Written in loginError Method to complete the exception handling operation :

    @GetMapping("/login/error")
    @ResponseBody
    public Result loginError(HttpServletRequest request) {
    
    AuthenticationException authenticationException = (AuthenticationException) request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    log.info("authenticationException={}", authenticationException);
    Result result = new Result();
    result.setCode(201);
    if (authenticationException instanceof UsernameNotFoundException || authenticationException instanceof BadCredentialsException) {
    
    result.setMsg(" Wrong user name or password ");
    } else if (authenticationException instanceof DisabledException) {
    
    result.setMsg(" User disabled ");
    } else if (authenticationException instanceof LockedException) {
    
    result.setMsg(" The account is locked ");
    } else if (authenticationException instanceof AccountExpiredException) {
    
    result.setMsg(" Account expired ");
    } else if (authenticationException instanceof CredentialsExpiredException) {
    
    result.setMsg(" Certificate expired ");
    } else {
    
    result.setMsg(" Login failed ");
    }
    return result;
    }
    

    modify CustomUserDetailsService loadUserByUsername() Return value of method :

     @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    // Retrieve user information from the database 
    SysUser user = userService.selectByName(username);
    // Judge whether the user exists 
    if(user == null) {
    
    throw new UsernameNotFoundException(" The username does not exist ");
    }
    // Add permissions 
    List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId());
    for (SysUserRole userRole : userRoles) {
    
    SysRole role = roleService.selectById(userRole.getRoleId());
    authorities.add(new SimpleGrantedAuthority(role.getName()));
    }
    // return UserDetails Implementation class 
    return new User(user.getUsername(), user.getPassword(),true,
    true,
    true,
    true,
    authorities);
    }
    

4. Run the project

When the account password is wrong :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-4vfxRcsV-1584085522208)(assets/1583778922802.png)]

copyright:author[Prodigal son Tang Shao],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/02/202202130729557982.html