Spring Security笔记

前言

配置Spring Security只需要继承WebSecurityConfigurerAdapter
权限登录登出相关重写configure(HttpSecurity http)方法,
用户验证重写configure(AuthenticationManagerBuilder auth)方法
this is 我的项目目录结构
在这里插入图片描述

1.权限控制相关

重写configure(HttpSecurity http)方法

  	antMatchers()方法,设置请求路径

    permitAll() 方法,所有用户可访问。
    denyAll() 方法,所有用户不可访问。
    authenticated() 方法,登录用户可访问。
    anonymous() 方法,无需登录,即匿名用户可访问。
    rememberMe() 方法,通过 remember me 登录的用户可访问。
    fullyAuthenticated() 方法,非 remember me 登录的用户可访问。
    hasIpAddress(String ipaddressExpression) 方法,来自指定 IP 表达式的用户可访问。
    hasRole(String role) 方法, 拥有指定角色的用户可访问。
    hasAnyRole(String... roles) 方法,拥有指定任一角色的用户可访问。
    hasAuthority(String authority) 方法,拥有指定权限(authority)的用户可访问。
    hasAuthority(String... authorities) 方法,拥有指定任一权限(authority)的用户可访问。
    access(String attribute) 方法,当 Spring EL 表达式的执行结果为 true 时,可以访问。
        http.authorizeRequests()
                .antMatchers("/xiHongShi").permitAll()
                .antMatchers("/xiHongShi/internet").authenticated() // 登录可访问
                .antMatchers("/xiHongShi/office").hasRole("区长"); // 区长可访问

2. 自定义登录,退出

继续操作configure(HttpSecurity http)方法,没有登录的情况下,如果不开启登录配置了访问权限,只会报错不会跳转到登录界面。开启登录功能之后,访问设有权限的url,会跳转到登录页。

		// 开启登录
 		http.formLogin()
                .loginPage("/login.html")   //自定义登录页面
                .loginProcessingUrl("/login")   // 登录访问路径
                .defaultSuccessUrl("/xiHongShi").permitAll() // 登陆成功跳转
                .and()
                .csrf().disable(); //关闭csrf防护
        // 开启退出
        http.logout()
                .logoutUrl("/logout") // 登出访问路径
                .logoutSuccessUrl("/xiHongShi") // 登出成功跳转
                .permitAll();

在内存中配置配置下用户密码,方便测试,在配置类中重写configure(AuthenticationManagerBuilder auth)方法

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("lacy").password(passwordEncoder().encode("lacy")).roles("admin");
    }
     @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

3.自定义全局异常处理

如果没有设置异常处理就是这个样子,所以简单处理一下
在这里插入图片描述
创建了自定义403的页面,403.html就是我创建的页面

//自定义异常处理
        http.exceptionHandling()
                .accessDeniedPage("/403.html");

此时权限不够的话会跳转到自定义的403.html页面。
但是现在都是前后端分离,跳转到其他页面显然很不合理,只需要发一条message就可以。于是我创建了全局异常处理器,可惜他并不能捕获Security所抛出的异常,找了半天,Security是一个过滤器链,全局异常处理器是处理controller跑出的异常,而Security抛出的异常并没有到controller那里就被处理,所以全局异常处理是不行的。这个图是借鉴的[这里]。(https://blog.csdn.net/zhangyongbink/article/details/112678052)
在这里插入图片描述
对于一个爱美人事,是不能这样善罢甘休的,所以找来了这两个接口,处理用户登录和权限相关的异常。AuthenticationEntryPoint,用来解决匿名用户访问无权限资源时的异常,AccessDeniedHandler,用来解决认证过的用户访问无权限资源时的异常。
创建一个SecurityExceptionHandler类实现这两个接口

@Component
public class SecurityExceptionHandler implements AuthenticationEntryPoint, AccessDeniedHandler {
    /**
     * AuthenticationEntryPoint的方法,用来解决匿名用户访问无权限资源时的异常
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().print("{\"msg\":\"commence-没有访问权限!\"}");
    }
    /**
     * AccessDeniedHandler,用来解决认证过的用户访问无权限资源时的异常
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().print("{\"msg\":\"handle-没有访问权限!\"}");
    }
}

在Security配置类的configure(HttpSecurity http)方法中添加,不要忘记注入

 	@Resource
    private SecurityExceptionHandler exceptionHandler;
        //自定义异常处理
        http.exceptionHandling()
//                .accessDeniedPage("/403.html");
                .authenticationEntryPoint(exceptionHandler) // 解决匿名用户访问无权限资源时的异常
                .accessDeniedHandler(exceptionHandler); // 解决认证过的用户访问无权限资源时的异常

此时此刻就正常了。
在这里插入图片描述

4.连接数据库

验证用户时是不会从内存中验证的,所以必须从数据库中查询。创建UserService实现UserDetailsService 并重写loadUserByUsername(String userName)方法。

@Service
public class UserService implements UserDetailsService {

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException{
        UserDo user = userRepository.getByName(userName);
        if(user == null){
            throw new BadCredentialsException("用户名不存在");
        }
        List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_"+user.getRole());
        return new User(user.getName(),passwordEncoder.encode(user.getPassword()),role);
    }
}

在刚才configure(AuthenticationManagerBuilder auth)的方法中修改
先注入bean ↓

	@Resource
	private UserService userService;
	// 验证用户
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //auth.inMemoryAuthentication().withUser("lacy").password(passwordEncoder().encode("lacy")).roles("dog");
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }


注:
数据库用户角色要前要添加“ROLE_”,验证时默认加该前缀。
在这里插入图片描述
底层重要的类与方法

// 方法级权限过滤器,位于过滤链底部
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter
// 异常过滤器,用于在验证过程中过滤异常
public class ExceptionTranslationFilter extends GenericFilterBean implements MessageSourceAware
// 对login的post请求做拦截 封装用户密码
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter
    
    
// 自定义校验 重写该接口
public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

// 加密密码
public interface PasswordEncoder {
    String encode(CharSequence var1);

    boolean matches(CharSequence var1, String var2);

    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}
// 验证用户名密码
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

// 干活的类
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware 
    // 进行身份验证
     public Authentication authenticate(Authentication authentication) throws AuthenticationException 
    
public Filter springSecurityFilterChain() throws Exception {
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值