Spring Boot与Spring Security

Spring Security

  Spring Security是专门针对基于Spring的项目的安全框架,充分利用了依赖注入和AOP来实现安全的功能,在早期的Spring Security的版本,使用Spring Security需要使用大量的XML配置,而SpringBoot中将全部基于Java配置和注解来实现Spring Security的功能
安全框架有两个重要概念,即认证(Authentication)和授权(Authorization),认证即确定用户可以访问当前系统,授权即确定用户在当前系统下所拥有的功能权限

用户认证

认证需要我们有一套用户数据的来源,而授权则是对于某个用户有相应的角色权限,在Spring Security里我们通过重写

protected void configure(AuthenticationManagerBuilder auth)

方法来实现定制

内存中的用户

使用AuthenticationManagerBuilder 的InMemoryAuthentication方法即可添加在内存中的用户,并可给用户指定角色权限

@Override
protected void configure (AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().WithUser("zhaozhen").password("zhaozhen").roles("ROLE_ADMIN")
    .add()
    .withUser("zhao")..password("1234").roles("ROLE_USER")
}

JDBC中的用户

JDBC中的用户直接指定dataSource即可

@Autowired
DataSource dataSource

@Override
protected void configure(AuthenticationManagerBuilder auth)throws Exception{
    auth.jdbcAuthentication().dataSourc(dataSource);
}

通用的用户

上面的两种用户和权限的获取方式只限于内存或者JDBC,我们的数据访问方式是多种多样的,可以是非关系型数据库,也可以是我们常用的JPA等
在此我们不再赘述,此种方式将在接下来的实践中介绍

SpringBoot的支持

  SpringBoot为SpringSecurity提供了许多的自动配置
比如:

  • 自动配置了一个内存中的user,密码在 程序运动时出现。
  • 忽略对js和css等静态文件的拦截。
  • 自动配置的securityFilterChainRegistration的Bean

我们也可以在properties配置以”security”为前缀的与Spring Security相关的配置

当我们需要自己扩展的配置,只需配置类继承WebSecurityConfigurerAdapter类即可,无需使用@EnableWebSecurity注解

实战

1.配置

application.properties

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

logging.level.org.springframework.security = INFO
spring.thymeleaf.cache=false

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true

pom.xml文件

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

用户和角色

用户
@Entity
public class SysUser implements UserDetails {
    @Id
    @GeneratedValue
    private  Long id;
    private  String username;
    private  String password;
    @ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
    private List<SysRole> roles;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<SysRole> getRoles() {
        return roles;
    }

    public void setRoles(List<SysRole> roles) {
        this.roles = roles;
    }

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

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

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

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

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

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

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

上述实体实现UserDetails接口,我们的用户实体即为Spring Security所使用的用户。重写了getAuthorities方法,将用户的角色作为权限

角色
@Entity
public class SysRole {
    @Id
    @GeneratedValue
    private  Long id;
    private  String name;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

}
传值对象

数据展示对象

public class Msg {
    private  String title;
    private  String content;
    private  String etraInfo;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getEtraInfo() {
        return etraInfo;
    }

    public void setEtraInfo(String etraInfo) {
        this.etraInfo = etraInfo;
    }

    public Msg(String title, String content, String etraInfo) {
        super();
        this.title = title;
        this.content = content;
        this.etraInfo = etraInfo;
    }
}
数据访问
public interface SysUserRepository extends JpaRepository<SysUser,Long>{
    SysUser findByUsername(String username);
}
自定义UserDetailsService
public class CustomerUserService implements UserDetailsService{
    @Autowired
    SysUserRepository sysUserRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser user = sysUserRepository.findByUsername(username);
        if (user == null){
            throw new UsernameNotFoundException("用户名不存在");
        }
        return  user;
    }
}

我们通过重写loadUserByUsername获得用户

配置
SpringMVC配置
@Configuration
public class WebMVCConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
    }
}
Spring Security配置
@Configuration
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter{
    @Bean
    UserDetailsService customerUserService(){
        return  new CustomerUserService();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest()
                .authenticated().and()
                .formLogin()
                    .loginPage("/login")
                    .failureUrl("/login?error")
                    .permitAll()
                .and()
                .logout().permitAll();

    }
}

我们定制登录和注销行为。
登录login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta content="text/html;charset=UTF-8"/>
    <title>登录页面</title>
    <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
    <style type="text/css">
        body {
            padding-top: 50px;
        }
        .starter-template {
            padding: 40px 15px;
            text-align: center;
        }
    </style>
</head>
<body>

<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <a class="navbar-brand" href="#">Spring Security演示</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
            <ul class="nav navbar-nav">
                <li><a th:href="@{/}"> 首页 </a></li>

            </ul>
        </div><!--/.nav-collapse -->
    </div>
</nav>
<div class="container">

    <div class="starter-template">
        <p th:if="${param.logout}" class="bg-warning">已成功注销</p><!-- 1 -->
        <p th:if="${param.error}" class="bg-danger">有错误,请重试</p> <!-- 2 -->
        <h2>使用账号密码登录</h2>
        <form name="form" th:action="@{/login}" action="/login" method="POST"> <!-- 3 -->
            <div class="form-group">
                <label for="username">账号</label>
                <input type="text" class="form-control" name="username" value="" placeholder="账号" />
            </div>
            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" class="form-control" name="password" placeholder="密码" />
            </div>
            <input type="submit" id="login" value="Login" class="btn btn-primary" />
        </form>
    </div>

</div>

</body>
</html>

首页

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" 
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"><!-- 1 -->
<head>
<meta content="text/html;charset=UTF-8"/>
<title sec:authentication="name"></title> <!-- 2 -->
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
<style type="text/css">
body {
  padding-top: 50px;
}
.starter-template {
  padding: 40px 15px;
  text-align: center;
}
</style>
</head>
<body>
     <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="#">Spring Security演示</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
           <li><a th:href="@{/}"> 首页 </a></li>

          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>


     <div class="container">

      <div class="starter-template">
        <h1 th:text="${msg.title}"></h1>

        <p class="bg-primary" th:text="${msg.content}"></p>

        <div sec:authorize="hasRole('ROLE_ADMIN')"> <!-- 3 -->
            <p class="bg-info" th:text="${msg.etraInfo}"></p>
        </div>  

        <div sec:authorize="hasRole('ROLE_USER')"> <!-- 4-->
            <p class="bg-info">无更多信息显示</p>
        </div>  

        <form th:action="@{/logout}" method="post">
            <input type="submit" class="btn btn-primary" value="注销"/><!-- 5 -->
        </form>
      </div>

    </div>


</body>
</html>

登陆界面
这里写图片描述

管理员登录所看到的内容
这里写图片描述

普通用户登录看到的内容
这里写图片描述
参考书籍JavaEE的颠覆者–SpringBoot实战代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值