Spring Security入门

523 阅读4分钟

概述

Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架。它是保护基于 Spring 的应用程序的事实上的标准

Spring Security 是一个专注于为 Java 应用程序提供身份验证和授权的框架。与所有 Spring 项目一样,Spring Security 的真正强大之处在于它可以轻松扩展以满足自定义要求

特征

  • 对身份验证和授权的全面且可扩展的支持
  • 防止会话固定、点击劫持、跨站点请求伪造等攻击
  • Servlet API 集成
  • 与 Spring Web MVC 的可选集成

实现

依赖

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

测试

@RestController
public class DemoController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello world";
    }
}

image.png

然后我们启动项目,按照我们正常的理解,直接访问

localhost:8080/hello

会返回hello world 。但结果却是重定向到了/login 。下面的界面是Spring security 自带的

image.png

其实上面可以看到,Spring security 已经起作用了,没有登录不能访问 /hello 接口

默认的用户名为 user

密码在我们项目启动时控制台有打印,每次都会不一样,随机生成的

image.png

image.png

可以看到,在登录之后,我们在请求 /hello 会直接返回hello world , 那是不是只要登录一次,后面就可以一直访问呢?当然不是的,登录成功之后,会将信息保存在session 中,再登录的时候,就会通过session 校验,这样就可以访问到了,当session过期获取我们手动清理掉后,就需要重新登录了

application.yml文件中的配置

spring:
  security:
    user:
      name: feiniu
      password: 123456
      roles: admin

分别是设置用户名,密码,角色。我们这里暂时只用了用户认证,所以角色设不设置无所谓

image.png

可以看到依然能够登陆成功,但是实际开发当中,我们并不使用这种方法进行配置

配置类进行配置

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                // 指定加密方式
                .passwordEncoder(passwordEncoder())
                .withUser("feiniu").password(passwordEncoder().encode("123456")).roles("admin")
                .and()
                .withUser("test").password(passwordEncoder().encode("123456")).roles("USER");
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        // BCryptPasswordEncoder:Spring Security 提供的加密工具
        return new BCryptPasswordEncoder();
    }
}

这里我们重写了configure(AuthenticationManagerBuilder auth) 方法,就是将定义的用户配置到内存中。这里有一个问题需要说明一下,就是这里配置的话,密码需要用BCryptPasswordEncoder 加密。如果不加密的话,项目编译启动不会报错,但是登陆的时候就会提示账号密码错误 如果我们在这配置了,那我们在application.peoperties 中配置的就会失效

上述的这两种都不常用,只是为了小编初步学习,所以列举了出来,我们在实际项目中根本不会在项目中写死用户信息的,基本上都是存在数据库中,所以下面我们就开始讲解我们最常用的模式

从数据库进行用户认证

既然是用到数据库,项目中自然要引入数据的配置,我这里用的是mysql 和mybatis

实体类

@Getter
@Setter
public class RolePO {
    private Long id;
    private String name;
}

我们在创建 UserEntry ,但是UserEntry 比较特殊,因为我们需要使用Spring security 。所以这里,UserEntry 需要实现 UserDetails

@Setter
@Getter
public class UserPO implements UserDetails {

    private Long id;
    private String username;
    private String password;
    private String nickname;
    private boolean enabled;
    private List<RolePO> roles;
    private String email;
    private String userface;
    private Timestamp regTime;

    /**
     * 获取角色权限
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (RolePO role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        }
        return authorities;
    }

    /**
     * 获取密码
     * @return
     */
    @Override
    public String getPassword() {
        return password;
    }

    /**
     * 获取用户名
     * @return
     */
    @Override
    public String getUsername() {
        return username;
    }


    /**
     * 用户账号是否过期
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 用户账号是否被锁定
     */
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    /**
     * 用户密码是否过期
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 用户是否可用
     */
    @Override
    public boolean isEnabled() {
        return enabled;
    }
}

然后写好mapper文件,mapper,dao,service

在service 层我们要注意一点,我们需要实现 UserDetailsService 接口。 我们先创建一个UserService 继承 UserDetailsService。然后创建一个UserServiceImpl 来时实现UserService 从而达到实现UserDetailsService的目的

service

public interface UserService extends UserDetailsService {
}

serviceImpl

@Service
@Slf4j
public class UserServiceImpl implements UserService {


    @Autowired
    UserMapper userMapper;

    @Autowired
    RolesMapper rolesMapper;


    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        UserPO user = userMapper.loadUserByUsername(s);
        if (user == null) {
            //避免返回null,这里返回一个不含有任何值的User对象,在后期的密码比对过程中一样会验证失败
            return new UserPO();
        }
        //查询用户的角色信息,并返回存入user中
        List<RolePO> roles = rolesMapper.getRolesByUid(user.getId());
        user.setRoles(roles);
        return user;
    }
}

SecurityConfig

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserService userService;


    @Bean
    public PasswordEncoder passwordEncoder() {
        // BCryptPasswordEncoder:Spring Security 提供的加密工具
        return new BCryptPasswordEncoder();
    }


    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService)
                .passwordEncoder(passwordEncoder());//passwoldEncoder是对密码的加密处理,如果user中密码没有加密,则可以不加此方法。注意加密请使用security自带的加密方式。
    }

然后启动项目,访问http://localhost:8080/hello, 就可以使用数据库当中user表和role表当中对应的用户和权限。

image.png

image.png

注意:下面给大家提供了一些配置项的参考内容,详情参考www.cnblogs.com/crazy-lc/p/…

image.png

今天的分享就到这里啦,希望能给你带来帮助!!!