面试必备技能,springsecurity

如果用户通过Spring Security进行登录,通常会涉及到以下四个类,并按照如下顺序进行处理:
1.WebSecurityConfigurerAdapter:首先会调用WebSecurityConfigurerAdapter中的configure(HttpSecurity http)方法,用于配置哪些URL需要被拦截,哪些URL不需要被拦截。如果用户访问一个受保护的URL,则Spring Security会重定向到登录页面。
2.UserDetailsService:当用户填写登录表单并点击“登录”按钮时,Spring Security会将表单中的用户名和密码传递给UserDetailsService类,以便验证用户是否有效。如果用户信息是有效的,该方法会返回一个实现了UserDetails接口的对象,表示已验证的用户。
3.AuthorizationServerConfigurerAdapter:如果用户信息是有效的,则Spring Security会创建一个OAuth2令牌并将其发送给客户端。这一步骤涉及到AuthorizationServerConfigurerAdapter类,其中定义了授权服务器的详细信息,包括客户端ID、客户端密钥、授权类型等等。
4.TokenConfig:最后,Spring Security会使用TokenConfig类来设置令牌的存储方式、过期时间等其他配置细节。在该类中,我们可以指定使用哪种TokenStore、TokenEnhancer等。
.总之,以上四个步骤结合在一起,可以实现用户认证和授权,并生成一个OAuth2令牌,一般都会使用jwt令牌来替代OAuth2令牌。
JWT是一个基于JSON格式的令牌,其中包含了关于用户、授权和其他元数据的声明。JWT可以使用私钥进行签名,确保其完整性和真实性,还可以使用公钥进行验证。由于JWT是自包含的,因此它们可以在不同系统之间轻松地传递,并且可以存储在客户端中而无需依赖服务器。另外,由于JWT已经被签名,所以它们通常不需要与授权服务器通信来验证其有效性,这使得JWT更具扩展性和灵活性

模块该如何吃透
权限认证
1,功能实现
业务功能实现:用户名密码登录、二维码登录,第三方用户登录、手机短信登录、用户、角色、权限管理和分配
●技术方案支撑:RBAC模型、Spring Security 或Apache Shiro
2,常见的问题
token刷新问题、密码的加密和解密、XSS防跨站攻击
3,权限系统设计
可扩展性、高可用性、通用性

手机短信登录

    @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();
		}
	}

}

第三方登录流程(以QQ登录其他系统为例子)

1.第三方QQ用户发起登录请求:当第三方QQ用户选择使用QQ登录我们的系统时,用户通过点击相关登录链接或按钮触发登录请求。

2.跳转至QQ登录页面:系统将生成一个包含授权请求的URL,并将用户重定向到QQ的登录页面。用户在该页面进行QQ账号的登录验证。

3.用户授权:登录成功后,QQ向用户展示所需授权信息的权限列表,用户同意授权请求,允许我们的系统访问其相关信息。

4.获取授权凭证code:QQ登录页面在用户授权成功后,将会将一个授权凭证code返回给我们的系统。该code是临时有效的,通常只能使用一次。

5.后端获取access token:我们的系统收到QQ返回的授权凭证code后,使用该code与QQ的授权服务器交互,并通过OAuth2协议获取访问令牌(access token)。此令牌用于后续对QQ API的调用进行认证。

6.获取用户信息:系统使用获得的access token与QQ的API服务器通信,请求获取用户的相关信息,如昵称、头像等。

7.验证用户身份:获取到用户信息后,系统可以根据自身业务逻辑对用户进行验证。此时可以使用Spring Security提供的UserDetailsService接口实现,该接口负责从数据库或其他数据源中获取用户的详细信息。

8.生成JWT令牌:如果用户已在系统中注册并通过验证,系统会生成一个JWT令牌。这里可以利用UserDetailsService从数据库中获取的用户信息,包括用户名、角色等,进行令牌的生成和签名。

9.返回JWT令牌:系统将生成的JWT令牌返回给前端客户端。客户端可以将令牌存储在Cookie或本地存储中,以便后续请求时携带。

10.后续请求的认证与授权:在用户完成登录后,其后续的请求将携带JWT令牌作为身份凭证。每次请求到达后端时,Spring Security会使用配置的JWT验证器来验证令牌的有效性,并从令牌中提取用户信息。

11.UserDetailsService的使用:在验证过程中,Spring Security使用UserDetailsService接口来加载用户的详细信息。该接口包含loadUserByUsername方法,通过用户名从数据库或其他数据源中加载用户信息。

token刷新问题,可以直接通过配置来解决

1.导入依赖

    <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.新建配置类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;
}

密码的加密和密码匹配

在WebSecurityConfigurerAdapter的子类中加入
@Autowired
PasswordEncoder passwordEncoder;
boolean matches = passwordEncoder.matches(inputPassword, password);

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

XSS防跨站攻击

XSS(跨站脚本攻击)是一种常见的Web应用程序安全漏洞,攻击者通过在受害者访问的网页中注入恶意脚本,从而达到获取用户敏感信息、窃取cookie等目的。

其中一个常见的方法是使用Thymeleaf等前端模板引擎,在显示用户输入内容时对其进行转义,以防止恶意脚本的注入。在Spring Security中,可以通过配置HttpSecurity对象来启用XSS保护机制,例如:

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

这将启用浏览器内置的XSS保护机制,如果检测到恶意脚本,则会自动将其阻止。

另外,Spring Security还提供了许多其他的安全策略和配置选项,如使用Content-Security-Policy(CSP)来限制页面中可执行的脚本来源,使用HttpOnly属性来限制cookie的访问权限等。这些机制可以帮助保护Web应用程序免受XSS攻击。

jwt令牌springsecurity框架默认会校验有无令牌和令牌的合法性

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

但是有一些业务有的接口需要登录有的接口不需要登录就可访问,如何解决?

 /**
  *  @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();//其余放行
 }

RBAC模型,分为资源和角色型(资源性权限扩展性强)

在服务中配置

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();
// }
 }

猜你喜欢

转载自blog.csdn.net/qq_56533553/article/details/130350631
今日推荐