博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringSecurity 学习总结
阅读量:6998 次
发布时间:2019-06-27

本文共 4486 字,大约阅读时间需要 14 分钟。

hot3.png

一些基础的知识可以参考以下连接:  讲真,这老哥写的很好,不过还有很多估计没写完,遗憾

本文章主要是一个大概的总结。

首先SpringSecurity是一个安全框架,它所做的事儿简单概括就是使用Filter对整个项目进行一个保护,

保护的内容就包括 认证 和 授权验证 如果单针对Filter的话 他包括 登陆认证,和对URL的权限验证, 登陆认证是在SpringSecurity的过滤器链中的AbstractAuthenticationProcessingFilter的子类来做的 具体步骤

请求进来->若干前置过滤器->AbstractAuthenticationProcessingFilter.doFilter()-> AbstractAuthenticationProcessingFilter.attemptAuthentication()->如果获取到了Authentication则继续往下执行,否则重定向到登陆页面.... 从attemptAuthentication方法中的认证操作是调用了AuthenticationManager的authenticate方法来进行登陆认证,然后会把用户提交的用户信息封装成AuthenticationToken的实例丢进去,在其中进行验证,验证成功则返回填充了相关信息的Token对象,否则是null,则说明认证失败,会重定向到我们设置好的loginUrl。

这个认证过程中还涉及到 AuthenticationManager 的认证 是 AuthenticationManager的一个实现类ProviderManager,而ProviderManager会有一个List专门存放Provider,这些Provider都要实现AuthenticationProvider接口,只要有一个Provider支持放进来的Authentication则会由这个Provider进行处理,且这个方法可以抛出异常,抛出也说明登陆失败。

所以如果要自定义自己的一套登陆认证的话,

我们涉及到三个地方 Filter - Provider - Token (例子采用上面链接的老哥的例子)

我们需要自定义自己的过滤器 通过 继承 AbstractAuthenticationProcessingFilter 类 实现 attemptAuthentication方法

public class IpAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {    public IpAuthenticationProcessingFilter(String uri) {        super(new AntPathRequestMatcher(uri));    }    @Override    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {        //获取host信息        String host = httpServletRequest.getRemoteHost();        //交给内部的AuthenticationManager去认证,实现解耦        return getAuthenticationManager().authenticate(new IpAuthenticationToken(host));    }}

我们需要自定义自己的认证提供器 通过继承 AuthenticationProvider 类

public class IpAuthenticationProvider implements AuthenticationProvider {    final static Map
ipAuthorityMap = new ConcurrentHashMap<>(); //维护一个ip白名单列表,每个ip对应一定的权限 static { ipAuthorityMap.put("127.0.0.1", new SimpleGrantedAuthority("ADMIN")); ipAuthorityMap.put("10.0.0.8", new SimpleGrantedAuthority("FRIEND")); } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { if (authentication instanceof IpAuthenticationToken){ String ip = ((IpAuthenticationToken)authentication).getIp(); if (ipAuthorityMap.containsKey(ip)){ HashSet
grants = new HashSet(); grants.add(ipAuthorityMap.get(ip)); return new IpAuthenticationToken(ip,grants); } } return null; } @Override public boolean supports(Class
aClass) { return IpAuthenticationToken.class.isAssignableFrom(aClass); }}

我们需要自定义自己的 认证对象 一般就是我们的领域对象 但是这个对象必须实现 Authentication 接口 我们可以直接继AbstractAuthenticationToken类即可

public class IpAuthenticationToken extends AbstractAuthenticationToken {    public String getIp() {        return ip;    }    public void setIp(String ip) {        this.ip = ip;    }    private String ip;    public IpAuthenticationToken(String ip) {        super(null);        this.ip = ip;        super.setAuthenticated(false);    }    public IpAuthenticationToken(String ip, Collection
authorities) { super(authorities); this.ip = ip; super.setAuthenticated(true); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return null; }}

然后我们需要将provider添加到ProviderManager的List中去

@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {    auth.authenticationProvider(new IpAuthenticationProvider());    auth.userDetailsService(userDetailsService).passwordEncoder(NoOpPasswordEncoder.getInstance());}

 将我们自定义的Filter注册到过滤器链中去

@Overrideprotected void configure(HttpSecurity http) throws Exception {    http        .authorizeRequests()            .antMatchers("/iplogin","/login").permitAll()            .anyRequest().authenticated()            .and()        .formLogin()        .loginPage("/iplogin");    //这个操作就是把我们自定义的过滤器插入到UsernamePasswordAuthenticationFilter的前面,表示优先使用我们的验证,如果验证成功则会将Authentication对象放入                    //SecurityContext中,后面的过滤器在进行验证时会检测SecurityContext中是否有相应的对象,没有则会    http.addFilterBefore(ipAuthenticationProcessingFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);}

搞定 这个时候我们的登陆验证方式已经改成了iplogin(虽然原始的login还在,但是由于我们设置了loginPage的url为/iplogin所以那个页面在登陆失败的时候永远也访问不到,除非你直接访问/login....)

转载于:https://my.oschina.net/u/3387406/blog/2999395

你可能感兴趣的文章