Necessary skills for interviews, springsecurity

If the user logs in through Spring Security, the following four classes are usually involved and processed in the following order:
1. WebSecurityConfigurerAdapter: First, the configure(HttpSecurity http) method in WebSecurityConfigurerAdapter is called to configure which URLs need to be intercepted. Which URLs do not need to be blocked. If the user visits a protected URL, Spring Security redirects to the login page.
2. UserDetailsService: When the user fills in the login form and clicks the "Login" button, Spring Security will pass the username and password in the form to the UserDetailsService class to verify whether the user is valid. If the user information is valid, this method returns an object that implements the UserDetails interface, representing the authenticated user.
3.AuthorizationServerConfigurerAdapter: If the user information is valid, Spring Security will create an OAuth2 token and send it to the client. This step involves the AuthorizationServerConfigurerAdapter class, which defines the details of the authorization server, including client ID, client secret, authorization type, and more.
4. TokenConfig: Finally, Spring Security will use the TokenConfig class to set the token storage method, expiration time and other configuration details. In this class, we can specify which TokenStore, TokenEnhancer, etc. to use.
.In short, the combination of the above four steps can realize user authentication and authorization, and generate an OAuth2 token. Generally, jwt tokens are used to replace OAuth2 tokens.
JWTis a JSON-based token that contains claims about the user, authorization, and other metadata. JWT can be signed with a private key, ensuring its integrity and authenticity, and can be verified with a public key. Since JWTs are self-contained, they can be easily passed between different systems and can be stored on the client side without relying on the server. In addition, since JWTs are already signed, they generally do not need to communicate with an authorization server to verify their validity, which makes JWTs more scalable and flexible

How to thoroughly understand the module
Authorization authentication
1, function realization
Business function realization: username and password login, QR code login, third-party user login, SMS login, user, role, permission management and allocation
Technical solution support: RBAC model, Spring Security or Apache Shiro
2, common problems
token refresh problem, password encryption and decryption, XSS anti-cross-site attack
3, permission system design
scalability, high availability, versatility

SMS login

    @PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user, HttpSession session){
    
    
        //获取手机号
        String phone = user.getPhone();

        if(StringUtils.isNotEmpty(phone)){
    
    
            //生成随机的4位验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            log.info("code={}",code);

            //调用阿里云提供的短信服务API完成发送短信
            //SMSUtils.sendMessage("瑞吉外卖","",phone,code);

            //将生成的验证码缓存到Redis中,并且设置有效期为5分钟
            redisTemplate.opsForValue().set(phone,code,5,TimeUnit.MINUTES);

            return R.success("手机验证码短信发送成功");
        }

        return R.error("短信发送失败");
    }
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;

/**
 * 短信发送工具类
 */
public class SMSUtils {
    
    

	/**
	 * 发送短信
	 * @param signName 签名
	 * @param templateCode 模板
	 * @param phoneNumbers 手机号
	 * @param param 参数
	 */
	public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){
    
    
		DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
		IAcsClient client = new DefaultAcsClient(profile);

		SendSmsRequest request = new SendSmsRequest();
		request.setSysRegionId("cn-hangzhou");
		request.setPhoneNumbers(phoneNumbers);
		request.setSignName(signName);
		request.setTemplateCode(templateCode);
		request.setTemplateParam("{\"code\":\""+param+"\"}");
		try {
    
    
			SendSmsResponse response = client.getAcsResponse(request);
			System.out.println("短信发送成功");
		}catch (ClientException e) {
    
    
			e.printStackTrace();
		}
	}

}

Third-party login process (take QQ login to other systems as an example)

1. A third-party QQ user initiates a login request: When a third-party QQ user chooses to use QQ to log in to our system, the user triggers a login request by clicking the relevant login link or button.

2. Jump to the QQ login page: The system will generate a URL containing an authorization request and redirect the user to the QQ login page. The user performs login verification of the QQ account on this page.

3. User authorization: After successful login, QQ will display the permission list of the required authorization information to the user, and the user agrees to the authorization request and allows our system to access its relevant information.

4. Obtain the authorization certificate code: After the user authorizes successfully on the QQ login page, an authorization certificate code will be returned to our system. This code is only valid temporarily and can usually only be used once.

5. Obtaining the access token at the backend: After receiving the authorization credential code returned by QQ, our system uses the code to interact with the authorization server of QQ, and obtains the access token (access token) through the OAuth2 protocol. This token is used to authenticate subsequent calls to the QQ API.

6. Obtaining user information: the system uses the obtained access token to communicate with the QQ API server, requesting to obtain relevant information of the user, such as nickname, avatar, etc.

7. Verify user identity: After obtaining user information, the system can verify the user according to its own business logic. At this point, you can use the UserDetailsService interface provided by Spring Security to implement it, which is responsible for obtaining the user's detailed information from the database or other data sources.

8. Generate JWT token: If the user has registered in the system and passed the verification, the system will generate a JWT token. Here you can use UserDetailsService to obtain user information from the database, including user name, role, etc., to generate and sign tokens.

9. Return JWT token: The system returns the generated JWT token to the front-end client. The client can store the token in a cookie or local storage so that it can be carried in subsequent requests.

10. Authentication and authorization of subsequent requests: After the user completes the login, the subsequent requests will carry the JWT token as the identity credential. Every time a request hits the backend, Spring Security uses the configured JWT validator to verify the validity of the token and extract user information from the token.

11. Use of UserDetailsService: During the authentication process, Spring Security uses the UserDetailsService interface to load user details. This interface contains the loadUserByUsername method, which loads user information from the database or other data sources by username.

The token refresh problem can be solved directly through configuration

1. Import dependencies

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

2. Create a new configuration class TokenConfig

//令牌管理服务 public class TokenConfig
@Bean(name="authorizationServerTokenServicesCustom")
public AuthorizationServerTokenServices tokenService() {
    
    
    DefaultTokenServices service=new DefaultTokenServices();
    service.setSupportRefreshToken(true);//支持刷新令牌
    service.setTokenStore(tokenStore);//令牌存储策略

    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
    service.setTokenEnhancer(tokenEnhancerChain);

    service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
    service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
    return service;
}

Encryption of passwords and password matching


Add @Autowired
PasswordEncoder passwordEncoder to the subclass of WebSecurityConfigurerAdapter ;
boolean matches = passwordEncoder.matches(inputPassword, password);

//public class WebSecurityConfig extends WebSecurityConfigurerAdapter
    @Bean
    public PasswordEncoder passwordEncoder() {
    
    
//        //密码为明文方式
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }

XSS anti-cross-site attack

XSS (Cross-Site Scripting Attack) is a common web application security vulnerability. Attackers inject malicious scripts into web pages visited by victims to obtain sensitive user information and steal cookies.

One of the common methods is to use front-end template engines such as Thymeleaf to escape user input when displaying it to prevent injection of malicious scripts. In Spring Security, the XSS protection mechanism can be enabled by configuring the HttpSecurity object, for example:

//WebSecurityConfig
@Override
protected void configure(HttpSecurity http) throws Exception {
    
    
    http
        .headers()
            .xssProtection()
                .block(true)
                .xssProtectionEnabled(true);
}

This will enable the browser's built-in XSS protection mechanism, which will automatically block malicious script if it is detected.

In addition, Spring Security also provides many other security policies and configuration options, such as using Content-Security-Policy (CSP) to limit the source of executable scripts in the page, using the HttpOnly attribute to limit cookie access, etc. These mechanisms can help protect web applications from XSS attacks.

The jwt token springsecurity framework will verify whether there is a token and the legitimacy of the token by default

		每次都会携带令牌,可以通过一下获得(令牌一般都会扩展存储一些用户信息)
        Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principalObj instanceof String) {
            //取出用户身份信息
            String principal = principalObj.toString();
            //将json转成对象
            XcUser user = JSON.parseObject(principal, XcUser.class);
            return user;
        }

But there are some services, some interfaces need to be logged in, and some interfaces can be accessed without logging in. How to solve it?

 /**
  *  @Configuration
 @EnableResourceServer
 @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
 public class ResouceServerConfig extends ResourceServerConfigurerAdapter
  */
 @Override
 public void configure(HttpSecurity http) throws Exception {
    
    
  http.csrf().disable()
          .authorizeRequests()
          .antMatchers("/r/**","/course/**").authenticated()//所有/r/**的请求必须认证通过
          .anyRequest().permitAll();//其余放行
 }

The RBAC model is divided into resource and role types (resource-based permissions are highly scalable)

Configure in the service

package com.xuecheng.content.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

/**
 * @description RBAC资源服务配置
 * @author Mr.M
 * @date 2022/10/18 16:33
 * @version 1.0
 */
 @Configuration
 @EnableResourceServer
 @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
 public class ResouceServerConfig extends ResourceServerConfigurerAdapter {
    
    

 /**
  *
  */
  //资源服务标识
  public static final String RESOURCE_ID = "xuecheng-plus";

  @Autowired
  TokenStore tokenStore;

  @Override
  public void configure(ResourceServerSecurityConfigurer resources) {
    
    
   resources.resourceId(RESOURCE_ID)//资源 id
           .tokenStore(tokenStore)
           .stateless(true);
  }

 @Override
 public void configure(HttpSecurity http) throws Exception {
    
    
  http.csrf().disable()
          .authorizeRequests()
//                .antMatchers("/r/**","/course/**").authenticated()//所有/r/**的请求必须认证通过
          .anyRequest().permitAll();//其余放行
 }
//RBAC角色服务配置
// @Override
// public void configure(HttpSecurity http) throws Exception {
    
    
//  http.authorizeRequests()
//          .antMatchers("/api/admin/**").hasRole("ADMIN")
//          .antMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
//          .anyRequest().authenticated();
// }
 }

Guess you like

Origin blog.csdn.net/qq_56533553/article/details/130350631