Spring Security使用和源码解析

本文详细介绍了Spring Security的认证过程,包括UsernamePasswordAuthenticationToken的生成、AuthenticationManager的认证处理以及SecurityContextHolder的核心组件。还探讨了Spring Security的核心过滤器链,如SecurityContextPersistenceFilter、FilterSecurityInterceptor等。此外,文章提到了如何开启Spring Security,处理多个安全配置,以及如何将自定义过滤器纳入Spring Security的过滤器链中。
摘要由CSDN通过智能技术生成

一个web工程,如果涉及到私人信息或不可公开的资源,则必然要对访问者做过滤和认证,访问者只能获取跟自己相关或有权限访问的信息,这就是我们所熟知的登陆。简单的登陆通常是这样实现的:提供一个登陆接口,和一个过滤器。登陆接口用来用户名和密码校验,并将用户信息保存在http session中。过滤器则用来拦截所有未经授权的访问。

@RestController
@RequestMapping("/login")
public class LoginController {

    public void login(HttpServletRequest request, HttpServletResponse response) {
        String json;
        PrintWriter out = response.getWriter();
        String user = request.getParameter("usr");
        String pwd= request.getParameter("password");      
        if (pwd.equals(getPasswordByUserName(user))) {
            request.getSession().setAttribute("user", user);
            json = "{\"success\":true}";
        }
        else {
            json = "{\"success\":false}";
        }
        out.print(json);
        out.flush;
        out.close;
    }

}
public class AuthenticationFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        if (!httpServletRequest.getServletPath().equals("/login")) {
            HttpSession session = ((HttpServletRequest) request).getSession(false);
            if (session == null || session.getAttribute("user") == null) {
                ((HttpServletResponse) response).setStatus(401);
                return;
            }
        }
        chain.doFilter(request, response);
    }

   
}

Spring security 作为一个强大且可高度定制化的认证和访问控制框架,是安全化 spring 应用的实际标准。它为Java应用提供认证和授权的功能,用户能够轻易地扩展以适应自己的需求。

Spring security 认证的过程


  1. 用户向url /login Post登陆请求,该请求从由loginPage指定的前台页面发送,携带表单参数username和password。(/login 是spring security 4 默认拦截的认证url,它并不指向任何物理资源,在spring security 4之前,该url是/j_spring_security_check,参数是j_username和j_password;可以通过login-processing-url自定义认证url。事实上,我们还可以绕过鉴权过滤器,直接向自定义的登陆rest接口post登陆请求,只要我们引入了spring security相关的包,所有认证的逻辑将会在request.login(username, password)里完成,如下所示)。
        @RequestMapping(value = "/my_login", method = RequestMethod.POST)
        public void login(@RequestParam("username") String username,
                          @RequestParam("password") String password,
                          HttpServletRequest request,
                          HttpServletResponse response) throws DmsException {
            try {
                request.login(username, password);
            }
            catch (ServletException e) {
                throw new MyException("0000", e);
            }
    
            request.getSession();
        }

     

  2. 根据传入的 username 和 password 生成 UsernamePasswordAuthenticationToken,AuthenticationManager接口的 authenticate 方法将对生成的Authentication进行认证处理。AuthenticationManager的默认实现类是ProviderManager,ProviderManager将认证委托给AuthenticatiionProvider处理。认证的本质是将Authentication和UserDetails中的用户信息进行比较。UserDetails包装的是拥有权限的用户信息,通常是从数据库中获取。
  3. UsernamePasswordAuthenticationFilter 过滤器在登陆成功后会通过SecurityContextHolder.getContext().setAuthentication() 将认证信息Authentication绑定到SecurityContext。
  4. 下一次请求时,过滤器链头的 SecurityContextPersistenceFilter 会从 Session 中获取已登陆用户信息并生成 Authentication,并将 认证信息对象绑定到 SecurityContext。如果是对需要权限的接口或资源的请求,Spring Security将从SecurityContext中获取用户的权限来判定是否可以访问该接口或资源。

Spring Security的核心组件


  • SecurityContextHolder,提供了一系列静态方法,代理一个SecurityContextHolderStrategy实例,方便用户对安全上下文的访问和设置。其初始化方法在静态块中被调用
        static {
    		initialize();
    	}    
        private static void initialize() {
    		if (!StringUtils.hasText(strategyName)) {
    			// Set default
                // 如果未设置strategyName属性,则默认使用ThreadLocal策略
    			strategyName = MODE_THREADLOCAL;
    		}
    
    		if (strategyName.equals(MODE_THREADLOCAL)) {
                // 线程局部变量安全持有策略,每个线程分别持有各自的SecurityContext
    			strategy = new ThreadLocalSecurityContextHolderStrategy();
    		}
    		else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
                // 可继承线程局部变量安全持有策略,每新起一个线程,则从父线程继承SecurityContext
    			strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
    		}
    		else if (strategyName.equals(MODE_GLOBAL)) {
                // 全局安全上下文持有策略,所有的实例都共享同一个SecurityContext
                // 适用于富客户端应用,如swing应用。
    			strategy = new GlobalSecurityContextHolderStrategy();
    		}
    		else {
    			// Try to load a custom strategy
                // 用户可以自定义一个SecurityContextHolderStrategy实现类
    			try {
    				Class<?> clazz = Class.forName(strategyName);
    				Constructor<?> customStrategy = clazz.getConstructor();
    				strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();
    			}
    			catch (Exception e
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值