学习:security登陆、认证、授权

设置账号和密码

第一种方法:配置文件(不常用)
application

spring.security.user.name=admin
spring.security.user.password=123

第二种方法:配置类
需要继承WebSecurityConfigurerAdapter

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //密码加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode("456");
        //登录认证

        auth.inMemoryAuthentication()
                .withUser("user")
                .password(encode)
                .roles("user");
    }
    @Bean
    public PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
}

整体逻辑:在security登录中,认证只有两个步骤事需要编程人员来做的:
1、获取用户信息
2、返回用户信息以及权限。
剩下的认证、判断等,全部由security内部完成(没怎么看源码,所以具体怎么完成的不太清楚)
实现:
第一,我需要一个用来给security内部返回用户信息的类,config
第二,我需要一个获取用户信息的类,service

config

@Configuration
@EnableWebSecurity
public class ConfigTest extends WebSecurityConfigurerAdapter{


    @Autowired
    private MyService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    }


    @Bean
    public PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }
}

这里继承WebSecurityConfigurerAdapter类,重写configure方法,这是一个空方法,这里的具体要实现什么功能主要看括号中的AuthenticationManagerBuilder,这是一个身份验证管理器,既然是身份验证管理器,我就需要给它一个身份,所以就引出了userDetailsService用户详细信息,现在转到MyService类。

@Service
public class MyService implements UserDetailsService{


    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException{
        QueryWrapper<com.tan.pojo.User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",s);
        com.tan.pojo.User user = userMapper.selectOne(wrapper);

        if(user==null){
            throw new UsernameNotFoundException("用户名不存在");
        }
        return new User(user.getUsername(),new BCryptPaswordEncoder().encode(user.getPassword()),auths);  //模拟加密,return加密后的密码

这里主要用于获取用户,可以看到loadUserByUsername方法中的前三行,使用了mybatisPlus来查找数据库中用户的相关信息赋给user。接下来就是判断是该用户是否存在,不存在就直接报出异常。存在就把当前用户通过上面ConfigTest类给放到AuthenticationManagerBuilder中,剩下的对比操作就由security来完成。

设置认证

根据学习需要来设置哪些网址可以不用登录就能访问,哪些需要登录才能访问。
重写源码中的http安全方法

protected void configure(HttpSecurity http) throws Exception {
    this.logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
    http.authorizeRequests((requests) -> {
        ((AuthorizedUrl)requests.anyRequest()).authenticated();
    });
    http.formLogin();
    http.httpBasic();
}

根据当前学习需要,重写后的代码

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.formLogin()   //启用自定义登录页面
            .loginPage("/login.html") //登录页面设置
            .loginProcessingUrl("/user/login").permitAll() //登录访问路径
            .defaultSuccessUrl("/test/index") //默认成功路径, 成功后跳转的地方.
            .and().csrf().disable(); //关闭csrf功能, security3默认关闭,security4默认开启

    http.authorizeRequests()
            .antMatchers("/test/index").permitAll()//给一些网站开绿灯,不需要认证也可以登录
            .anyRequest().authenticated(); //所有网站都要需要认证
    http.formLogin();

    http.httpBasic();
}

这里遇到了一个问题,我重写了此方法之后,原方法中的anyRequest().authenticated();就失效了,所以在设置认证登录的时候,要把这一句话给加上,而且要加在认证的最后面,不然会报错

Error creating bean with name 'springSecurityFilterChain' defined in class path resource 
[org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: 
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; 
nested exception is java.lang.IllegalStateException: Can't configure antMatchers after anyRequest

可以看到最后一句,嵌套异常为无法在anyRequest之后配置antMatchers。


还有一点自己认为的疑问。。为什么不能把所有网站都需要认证这个条件默认开启,然后写一个关闭的方法,感觉这样更清晰一点。。


在WebSecurityConfigurerAdapter类中还有一些HttpSecurity的其他方法:

private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
    http.csrf(); //csrf功能,默认开启
    http.addFilter(new WebAsyncManagerIntegrationFilter()); //过滤器
    http.exceptionHandling();  //异常处理
    http.headers(); //安全头
    http.sessionManagement(); //会话管理器
    http.securityContext();  //存储当前用户账号信息和相关权限
    http.requestCache(); //请求缓存
    http.anonymous(); //匿名
    http.servletApi(); //小服务程序API
    http.apply(new DefaultLoginPageConfigurer()); //默认登录页面配置器
    http.logout(); //退出
}

三、设置授权

授权的方式分为以下四种:
1、hasAuthority
实现:
设置访问权限:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

设置用户权限:

http.authorizeRequests()
        .antMatchers("/test/hello").hasAnyAuthority("admin") 

缺点:只能对一个用户添加一个权限。

2、hasAnyAuthority
hasAuthority的升级版,解决了hasAuthority的缺点。
实现:
设置访问权限:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

设置用户权限:

http.authorizeRequests()
        .antMatchers("/test/hello").hasAnyAuthority("admin","user") 

3、hasRole
与hasAuthority不同的是需要在设置访问权限的时候添加一个前缀:ROLE_**
实现:
设置访问权限:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_vvv");

设置用户权限:

http.authorizeRequests()
        .antMatchers("/test/hello").hasRole("vvv")

这里需要注意一下,当使用hasRole时,不能在用户权限中设置ROLE_ 为前缀的权限,会报嵌套异常。


4、hasAnyRole
相当于是hasRole和hasAnyAuthority的结合,一个用户可以有多个权限,但是设置访问权限的时候需要加前缀ROLE_**
实现:
设置访问权限:

List<GrantedAuthority> auths = 
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");

设置用户权限:

http.authorizeRequests()
        .antMatchers("/test/hello").hasAnyRole("admin","aaa")
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值