spring security 入门(1) 简单登录配置及用户验证

JAVA学习网 2021-01-27 07:45:02

1、引入spring security

spring boot环境下,pom.xml需要加入spring security相关依赖即可启动spring security

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>

此时spring security使用默认配置,使用spring security默认登录页

此时默认用户名为:user,密码则输出来在启动时的命令行中

2、三种用户配置的方式

2.1、配置文件配置用户

在spring boot配置文件application.yml中配置:

spring:
security:
  user:
    name: user
    password: 456
    roles: admin

即可使用自定义用户登录,其中name为用户名,password为密码,roles为角色名,多个角色名用英文字符:,分割

2.2、使用将用户列表写入内存方式登录

此方法需要重新编写一个类,继承org.springframework.security.config.annotation.web.configuration中的WebSecurityConfigurerAdapter,并重写configure(AuthenticationManagerBuilder auth)方法

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.inMemoryAuthentication()
          .passwordEncoder(new BCryptPasswordEncoder())//配置密码加密方式,必须与之后密码加密方式一致,不然会登录失败,而且新版中必须设置,不然虽然编译不会报错,使用时会报java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
          .withUser("admin")//用户名
          .password(new BCryptPasswordEncoder().encode("123"))//密码
          .roles("admin")//角色名
          .and()
              .withUser("user")
          .password(new BCryptPasswordEncoder().encode("123"))
          .roles("vip","user");//多个角色时,直接放入多个变量,此函数参数String...
  }
}

上面代码定义了用户名为:admin,密码为:123,角色为admin 和 用户名为:user,密码为:123,角色为:vip和user的两个用户

此方法会在程序开始运行时就将用户列表写入内存,如需连接数据库,可以将所有用户查询出来后都写入内存,不过用户多的话这种方式比较耗内存,不推荐使用

@Autowired
private UsersService usersService;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  List<Users> listUser = usersService.findAll();
  for (Users users : listUser) {
      auth.inMemoryAuthentication()
              .passwordEncoder(new BCryptPasswordEncoder())
              .withUser(users.getAccountName()).password(new BCryptPasswordEncoder().encode(users.getPassword())).roles("admin","vip");
  }
}

这里因为测试没有关联出来角色权限,所以统一给admin和vip角色,可以也从数据库中查出来赋值角色,如赋值权限,可以用.authorities代替roles

2.3、使用AuthenticationManagerBuilder自带数据库方法登录

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


   //使用AuthenticationManagerBuilder自带jdbcAuthentication查询数据库登录
   @Autowired
   private DataSource dataSource;

   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.jdbcAuthentication()
              .dataSource(dataSource)
              .usersByUsernameQuery("select account_name,password,enable from users WHERE account_name=?")//设置根据账号名查找账户密码的sql语句
              .authoritiesByUsernameQuery("select account_name, authority from authorities where account_name=?")//设置根据账号名查找权限的sql语句
              .passwordEncoder(new BCryptPasswordEncoder());
  }
}

此方法使用sql直接查找数据库中的账号密码权限,如果不设置sql语句,默认查找账号语句是select username,password,enabled from users where username = ?,查找权限语句是select username,authority from authorities where username = ?,如果数据库结构不一致,就需要自己设置sql语句。由于sql的入参只有username,一般会比较麻烦。同时数据库中密码字段需要保存已加密数据。

2.4、使用实现UserDetailService接口方法设置用户

@Service("UserDetailsService")
public class MyUserDetailService implements UserDetailsService {
   @Autowired
   private UsersService usersService;

   @Override
   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
       //数据库查找账号,这里权限固定写admin和vip2个,没有查找数据库,需要的话直接查出来赋值就可以了
       //List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,vip");//生成权限列表,多个权限使用英文字符,隔开
       List<GrantedAuthority> auths = AuthorityUtils.createAuthorityList("admin","vip");//生成权限列表,
       Users users = usersService.findOneByAccountName(username);
       if(users == null){
           throw new UsernameNotFoundException("找不到该用户");
      }
       //返回org.springframework.security.core.userdetails.User对象,如不查数据库也可以直接对比用户名并返回需要的账号、密码和权限。如有返回值,spring security不会再比较用户名而只比较密码等信息,因此不要不比较用户名直接返回。
       return new User(users.getAccountName(),new BCryptPasswordEncoder().encode(users.getPassword()),true,true,true,true,auths);
  }
}

此方法需实现org.springframework.security.core.userdetails.UserDetailsService并重写loadUserByUsername方法,此方法需要返回一个org.springframework.security.core.userdetails.UserDetails,此处返回的org.springframework.security.core.userdetails.User类是UserDetails的实现类。此方法会在每次用户登录的时候传入username并一定程度上自定义登录逻辑。此方法仍需重写WebSecurityConfigurerAdapter的configure(AuthenticationManagerBuilder auth)方法。

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
   @Autowired
   private UserDetailsService userDetailsService;

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

3、登录配置

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
   protected void configure(HttpSecurity http) throws Exception {
       http
          .formLogin()//开启表单设置
              .loginPage("/login.html")//自定义登录页面链接
              .loginProcessingUrl("/login")//自定义登录页面form提交处理方法,不用特别写方法spring security会自动实现,,默认为/login,如需改其他,需要关闭csrf
              .defaultSuccessUrl("/")//设置默认登录成功跳转页面
              .passwordParameter("password")//设置form表单中提交的密码字段参数名,默认为password
              .usernameParameter("username")//设置form表单中提交的账户名字段参数名,默认为username
              .failureUrl("/login?error")//设置默认登录失败跳转页面
          .and()
          .authorizeRequests()//设置各请求的权限要求
              .antMatchers("/login","/login.html")//设置指定资源,参数为可变长度参数
                  .permitAll()//允许所有人(包括未登录的人访问
              .antMatchers("/hello/**","/")//**表示该目录及子目录下所有资源
                  .hasAuthority("admin")//要求有admin权限者才能访问
              .antMatchers("/test")
                  .hasAnyAuthority("user","admin")//要求有admin或user权限者才能访问
              .antMatchers("/vip")
                  .hasRole("vip")//要求有vip角色者才能访问
//               .hasIpAddress()指定IP地址可访问
//               .hasAnyRole()//类似hasAnyAuthority,但要求是某个或某几个权限才可以访问
              .anyRequest()
                  .authenticated()//必须登录后才能访问
          .and()
          .rememberMe()//开启记住我功能
              .rememberMeParameter("remeber")//设置form表单中提交的记住我字段参数名
          .and()
          .csrf().disable()//关闭csrf防御功能
      ;
  }
}

重写WebSecurityConfigurerAdapter的configure(HttpSecurity http)方法,根据自己的需求配置好,这里只是基础配置。



阅读(758) 评论(0)