Spring Security 业务级知识点整理

这一篇主要是对SpringSecurity的知识点梳理。
之前项目里面使用了一套登录验证,逻辑上与SpringSecurity的类似,基于WebService接口访问,我的那种是基于Token实现每次验证,通过Role确定方法的访问权限,在这里进行一个SpringSecurity的实现以及扩展。

一 前言

整个梳理包括以下几个部分

  • 开启security,并且配置访问
  • 自定义登录成功 / 失败 处理器
  • 定义自定义拦截器
  • 定义方法访问权限

二 详情

2.1 开启springSecurity 支持
2.1.1 依赖
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    。。。。省略。。。
    
    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
        
2.1.2 开启springSecurity支持及配置

这里主要是基于数据库的账户查询,所以先说相关的实体类。
主要有两个User 和Roles

@Entity
public class Users implements UserDetails {

    @Id
    @GeneratedValue
    private Long id;
    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)
    private List<Roles> roles;



    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        List<Roles> roles = this.getRoles();
        for (Roles role : roles) {
            auths.add(new SimpleGrantedAuthority(role.getName()));
        }
        return auths;

    }


    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
	。。。省略getter / setter
}

注意其中的方法:

方法作用
getAuthorities()
isAccountNonExpired()账户未过期
isAccountNonLocked()账户未锁定
isCredentialsNonExpired()证书未过期
isEnabled()账户已启用

当不准备手动配置的时候,这四项应该都返回的是True

Roles就比较简单了

@Entity
public class Roles {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

	。。。省略getter /  setter
}

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

}

类上的操作主要有两个,使用@EnableWebSecurity注解以及继承WebSecurityConfigurerAdapter。

然后说说里面的配置方法

方法作用
protected void configure(AuthenticationManagerBuilder auth)
protected void configure(HttpSecurity http)
public void configure(WebSecurity web)

看一下方法

2.1.3 对springSecurity进行配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    private AuthenticationFailureHandler myAuthenctiationFailureHandler;

    @Bean
    public UserService CustomerUserService() {
        System.out.print("step1============");
        return new UserService();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //该方法用于用户认证,此处添加内存用户,并且指定了权限
//        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
//                .withUser("user1").password(new BCryptPasswordEncoder().encode("123456")).roles("USER")
//                .and()
//                .withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("ADMIN");
        auth.userDetailsService(CustomerUserService()).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //此方法中进行了请求授权,用来规定对哪些请求进行拦截
        //其中:antMatchers--使用ant风格的路径匹配
        //regexMatchers--使用正则表达式匹配
        http.authorizeRequests()
                .antMatchers("/test/**").permitAll()
                .antMatchers("/before/**").permitAll()
                .antMatchers("/index").permitAll()
                .antMatchers("/").permitAll()							//以上是ant风格的过滤器
                .anyRequest().authenticated()                      //其它请求都需要校验才能访问
                .and()
                .formLogin()											//定义表单登录
                .loginPage("/login")                            	 //定义登录的页面"/login",允许访问
                .defaultSuccessUrl("/home")  				//登录成功后默认跳转到"list"
                .successHandler(myAuthenticationSuccessHandler)			//定义成功处理函数
                .failureHandler(myAuthenctiationFailureHandler)					//定义失败处理函数
                .permitAll()
                .and()
                .logout()                                         	  //默认的"/logout", 允许访问
                .logoutSuccessUrl("/index")
                .permitAll();
		//进行自定义filter
        http.addFilterBefore(new BeforeFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //解决静态资源被拦截的问题
        web.ignoring().antMatchers("/**/*.js", "/lang/*.json", "/**/*.css", "/**/*.js", "/**/*.map", "/**/*.html", "/**/*.png");
    }
}

2.1.4 自定义filter

当我们需要知道请求的拦截内容的时候可以通过自定义filter来实现

通过继承GenericFilterBean 重写方法实现


public class BeforeFilter extends GenericFilterBean {

    private Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        logger.info("This is a filter before UsernamePasswordAuthenticationFilter.");
        logger.info("getRemoteHost:{}",servletRequest.getRemoteHost());
        logger.info("getContentType:{}",servletRequest.getContentType());
        logger.info("getLocalName:{}",servletRequest.getLocalName());
        logger.info("getLocalAddr:{}",servletRequest.getLocalAddr());
        logger.info("getServerName:{}",servletRequest.getServerName());
        logger.info("getServerName:{}",servletRequest.getRemoteAddr());
        logger.info("getServerName:{}",servletRequest.getServletContext());
//        CommonUtils.reflect(servletRequest);
        // 继续调用 Filter 链
        filterChain.doFilter(servletRequest, servletResponse);

    }
}
2.1.5 定义成功已经失败处理器

登录失败处理器

@Component("myAuthenctiationFailureHandler")
public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    // AuthenticationException 认证过程中产生的异常
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        logger.info("MyAuthenticationSuccessHandler login failure!");
        logger.info(exception.getMessage());
        logger.info(exception.getLocalizedMessage());
        exception.printStackTrace();
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        response.setContentType("application/json;charset=UTF-8");
    }
}

登录成功处理器

@Component("myAuthenticationSuccessHandler")
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private UserLogService logService;
    @Autowired
    private UserService userService;


    // Authentication  封装认证信息
    // 登录方式不同,Authentication不同
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws ServletException, IOException {
        logger.info("MyAuthenticationSuccessHandler login success!");
        response.setContentType("application/json;charset=UTF-8");         // 把authentication对象转成 json 格式 字符串 通过 response 以application/json;charset=UTF-8 格式写到响应里面去
        response.getWriter().write(objectMapper.writeValueAsString(authentication));
        logger.info((String)request.getSession().getAttribute("username"));
//        Users user  =  userService.findUserByName((String)request.getSession().getAttribute("username"));
//        CommonUtils.reflect(user);
//        logService.save(new UserLog(String.valueOf(user.getId()),user.getUsername(),"名称为" +user.getUsername() + "的用户登录成功,登录IP为" + request.getRemoteAddr(),new Date()));
        // 父类的方法 就是 跳转
        super.onAuthenticationSuccess(request, response, authentication);

    }
}

参考:
https://www.cnkirito.moe/spring-security-1/
http://www.spring4all.com/article/419

未完待续。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值