天天看点

Spring Boot(十四)Spring Boot中使用Security实现权限控制

大家好,我是“追梦蜗牛”,大家可以在公众号后台回复 “Java资料”获得技能提升的资料,绝对是干货。

前言

(一). 什么是Spring Security? 

(二). 相关配置

(三). Spring Security实战

上篇文章为大家讲述了 Spring Boot中 数据缓存的使用;本篇文章接着上篇内容继续为大家介绍SpringBoot中 实现权限控制。

Spring Boot(十四)Spring Boot中使用Security实现权限控制

在web应用开发中,安全无疑是十分重要的,选择Spring Security来保护web应用是一个非常好的选择。Spring Security 是spring项目之中的一个安全模块,可以非常方便与spring项目无缝集成。特别是在spring boot项目中加入spring security更是十分简单。本篇我们介绍spring security,以及spring security在web应用中的使用。

Spring Security,这是一种基于 Spring AOP 和 Servlet 过滤器的安全框架。它提供全面的安全性解决方案,同时在 Web 请求级和方法调用级处理身份确认和授权。

http.authorizeRequests()     .anyRequest().authenticated()     .and()     .formLogin()     .and()

          //开启cookie保 用户数据

          .rememberMe()

          //设置cookie有效期

          .tokenValiditySeconds(60 * 60 * 24 * 7)

          //设置cookie的私钥

          .key("")

          .logout()

          //默认注销行为为logout,可以通过下面的方式来修改

           .logoutUrl("/custom-logout")

          //设置注销成功后跳转页面,默认是跳转到登录页面

          .logoutSuccessUrl("")

     .loginPage("/login")     .permitAll()

    .antMatchers("/resources/**", "/signup", "/about")

    .antMatchers("/admin/**")

    .hasRole("ADMIN")     .antMatchers("/db/**")

    .access("hasRole('ADMIN') and hasRole('DBA')")     .anyRequest()

    .authenticated()     .httpBasic();

http.authorizeRequests()方法有多个子节点,每个匹配器按其声明

的顺序进行考虑。上面列出了常用的基本配置,包括请求授权,登录页面路径,

成功后跳转等

  • 1.http.authorizeRequests()方法有多个子节点,每个匹配器按其声明的顺序进行考虑。
  • 2我们指定了任何用户都可以访问的多种URL模式。具体来说,如果URL以“/ resources /”开头,等于“/ signup”或等于“/ about”,则任何用户都可以访问请求。
  • 3 任何以“/ admin /”开头的URL都将仅限于具有“ROLE_ADMIN”角色的用户。您会注意到,由于我们正在调用hasRole方法,因此我们不需要指定“ROLE_”前缀。
  • 4 任何以“/ db /”开头的URL都要求用户同时拥有“ROLE_ADMIN”和“ROLE_DBA”。您会注意到,由于我们使用的是hasRole表达式,因此我们不需要指定“ROLE_”前缀。
  • 5 任何尚未匹配的URL只需要对用户进行身份验证

#创建项目

Spring Boot(十四)Spring Boot中使用Security实现权限控制
Spring Boot(十四)Spring Boot中使用Security实现权限控制
Spring Boot(十四)Spring Boot中使用Security实现权限控制

#数据库配置

我们这里还是通过mysql数据库来实现,配置数据库依赖

<dependency>              <groupId>mysql</groupId>              <artifactId>mysql-connector-java</artifactId>              <version>5.1.40</version>              </dependency>           

配置数据库 application.properties

spring.datasource.driver-class-name=com.mysql.jdbc.Driver              spring.datasource.url=jdbc:mysql://localhost:3306/springbootsecurity?useUnicode=true&characterEncoding=utf-8              spring.datasource.username=root              spring.datasource.password=root                  logging.level.org.springframework.security=info              spring.thymeleaf.cache=false              spring.jpa.hibernate.ddl-auto=update              spring.jpa.show-sql=true              spring.jackson.serialization.indent_output=true           

#用户和角色

我们使用JPA来定义用户和角色

package org.cxzc.myyoung.springbootsecurity;                  import org.springframework.security.core.GrantedAuthority;              import org.springframework.security.core.authority.SimpleGrantedAuthority;              import org.springframework.security.core.userdetails.UserDetails;                  import javax.persistence.*;              import java.util.ArrayList;              import java.util.Collection;              import java.util.List;                  @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<>();              List<SysRole> roles = this.getRoles();              for (SysRole role : roles) {              auths.add(new SimpleGrantedAuthority(role.getName()));              }              return auths;              }                  @Override              public String getPassword() {              return this.password;              }                  @Override              public String getUsername() {              return this.username;              }                  @Override              public boolean isAccountNonExpired() {              return true;              }                  @Override              public boolean isAccountNonLocked() {              return true;              }                  @Override              public boolean isCredentialsNonExpired() {              return true;              }                  @Override              public boolean isEnabled() {              return true;              }              }           

1,用户实体实现UserDetails接口,用户实体为spring security所使用的用户

2,配置用户和角色的多对多关系

3,重写 getAuthorities 方法,将用户的角色作为权限

#角色类

package org.cxzc.myyoung.springbootsecurity;                  import javax.persistence.Entity;              import javax.persistence.GeneratedValue;              import javax.persistence.Id;                  @Entity              public class SysRole {              @Id              @GeneratedValue              private Long id;              private String name;                      public Long getId() {              return id;              }                  public void setId(Long id) {              this.id = id;              }                  public String getName() {              return name;              }                  public void setName(String name) {              this.name = name;              }              }           

1,ID为自动生成

2,name为角色名称

#数据结构及初始化

上面两个实体类创建的目的就是为了 生成需要的数据表,这时会生成三张表

Spring Boot(十四)Spring Boot中使用Security实现权限控制

用户表:SYS_USER

角色表:SYS_ROLE

关联表:SYS_USER_ROLES

针对上面的三张表,创建一些数据来验证,数据创建格式如下:

insert  into `sys_role`(`id`,`name`) values (1,'ROLE_ADMIN'),(2,'ROLE_USER');              insert  into `sys_user`(`id`,`password`,`username`) values (1,'root','root'),(2,'chen','chen');              insert  into `sys_user_roles`(`sys_user_id`,`roles_id`) values (1,1),(2,2);           

创建两个用户,角色分别为 ROLE_ADMIN 和ROLE_USER

#传值对象

用来测试不同角色用户的数据展示。

package org.cxzc.myyoung.springbootsecurity;                  public class Msg {              private String title;              private String content;              private String extraInfo;                  public Msg() {              }                  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 getExtraInfo() {              return extraInfo;              }                  public void setExtraInfo(String extraInfo) {              this.extraInfo = extraInfo;              }                  public Msg(String title, String content, String extraInfo) {              this.title = title;              this.content = content;              this.extraInfo = extraInfo;              }              }           

#访问数据

package org.cxzc.myyoung.springbootsecurity;                  import org.springframework.data.jpa.repository.JpaRepository;                  public interface SysUserRepository extends JpaRepository<SysUser              , Long> {              SysUser findByUsername(String username);              }           

这里的访问权限很简单,这里只有一个通过用户名称,查询用户的方法。

#自定义UserDetailService

package org.cxzc.myyoung.springbootsecurity;                  import org.springframework.beans.factory.annotation.Autowired;              import org.springframework.security.core.userdetails.UserDetails;              import org.springframework.security.core.userdetails.              UserDetailsService;              import org.springframework.security.core.userdetails              .UsernameNotFoundException;                  public class CustomUserService implements UserDetailsService {              @Autowired              SysUserRepository userRepository;              @Override              public UserDetails loadUserByUsername(String s)               throws UsernameNotFoundException {              SysUser user = userRepository.findByUsername(s);              if (user == null) {              throw new UsernameNotFoundException("用户名不存在");              }              System.out.println("s:"+s);              System.out.println("username:"+user.getUsername()              +";password:"+user.getPassword());              return user;              }              }           

1,自定义 这里我们需要重写UserDetailsService接口

2,重写 loadUserByUsername 方法获得用户

3,实现重写接口中的loadUserByUsername方法,通过该方法查询到对应的用户,这里之所以要实现UserDetailsService接口,是因为在Spring Security中我们配置相关参数需要UserDetailsService类型的数据。

#Spring MVC配置

package org.cxzc.myyoung.springbootsecurity;                  import org.springframework.context.annotation.Configuration;              import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;              import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;                  @Configuration              public class WebMvcConfig extends WebMvcConfigurationSupport {              @Override              public void addViewControllers(ViewControllerRegistry registry) {              registry.addViewController("/login").setViewName("login");              }              }           

1,注册访问/login 转向login.html页面

#Spring Security 配置

package org.cxzc.myyoung.springbootsecurity;                  import org.springframework.context.annotation.Bean;              import org.springframework.context.annotation.Configuration;              import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;              import org.springframework.security.config.annotation.web.builders.HttpSecurity;              import org.springframework.security.config.annotation.web.builders.WebSecurity;              import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;              import org.springframework.security.core.userdetails.UserDetailsService;                  @Configuration              public class WebSecurityConfig extends WebSecurityConfigurerAdapter {              @Bean              UserDetailsService customUserService() {              return new CustomUserService();              }                  @Override              protected void configure(AuthenticationManagerBuilder auth) throws Exception {              auth.userDetailsService(customUserService());              }                  @Override              protected void configure(HttpSecurity http) throws Exception {              http.authorizeRequests()              .anyRequest().authenticated()              .and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll().and()              .logout().permitAll();              }              }           
1.首先当我们要自定义Spring Security的时候我们需要继承自              WebSecurityConfigurerAdapter来完成,相关配置重写对应 方法即可。              2.我们在这里注册CustomUserService的Bean,然后通过重写configure              方法添加我们自定义的认证方式。              3.在configure(HttpSecurity http)方法中,我们设置了登录页面,              而且登录页面任何人都可以访问,然后设置了登录失败地址,也设置了注销请求,              注销请求也是任何人都可以访问的。              4.permitAll表示该请求任何人都可以访问,.anyRequest().authenticated(),              表示其他的请求都必须要有权限认证。              5.这里我们可以通过匹配器来匹配路径,比如antMatchers方法,              假设我要管理员才可以访问admin文件夹下的内容,我可以这样来写:              .antMatchers("/admin/**").hasRole("ROLE_ADMIN"),              也可以设置admin文件夹下的文件可以有多个角色来访问,              写法如下:.antMatchers("/admin/**").              hasAnyRole("ROLE_ADMIN","ROLE_USER")              6.可以通过hasIpAddress来指定某一个ip可以访问该资源,              假设只允许访问ip为210.210.210.210的请求获取admin下的资源,              写法如下.antMatchers("/admin/**").hasIpAddress("210.210.210.210")              7.更多的权限控制方式参看下表:           
Spring Boot(十四)Spring Boot中使用Security实现权限控制

#创建登录界面

在template文件夹中创建login.html页面

<!DOCTYPE html>              <html lang="en" xmlns:th="http://www.thymeleaf.org">              <head>              <meta charset="UTF-8"/>              <title>登录</title>              <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>              <link rel="stylesheet" th:href="@{css/signin.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>              <li><a th:href="@{http://www.baidu.com}">百度</a></li>              </ul>              </div>              </div>              </nav>              <div class="container">              <div class="starter-template">              <p th:if="${param.logout}" class="bg-warning">已注销</p>              <p th:if="${param.error}" class="bg-danger">有错误,请重试</p>              <h2>使用账号密码登录</h2>              <form class="form-signin" role="form" name="form" th:action="@{/login}" action="/login" method="post">              <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>           

界面效果不多说,比较简单,就是一个简单登录界面,失败的提示等

#首页

在template文件夹中创建index.html页面

<!DOCTYPE html>              <html lang="en" xmlns:th="http://www.thymeleaf.org"              xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">              <head>              <meta charset="UTF-8"/>              <title sec:authentication="name"></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>              <li><a th:href="@{http://www.baidu.com}">百度</a></li>              </ul>              </div>              </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')">              <p class="bg-info" th:text="${msg.extraInfo}"></p>              </div>              <div sec:authorize="hasRole('ROLE_USER')">              <p class="bg-info">无更多显示信息</p>              </div>              <form th:action="@{/logout}" method="post">              <input type="submit" class="btn btn-primary" value="注销"/>              </form>              </div>              </div>              </body>              </html>           

1.在html标签中我们引入的Spring Security

2.通过sec:authentication="name"我们可以获取当前用户名

3.sec:authorize="hasRole('ROLE_ADMIN')表示当前用户角色为ROLE_ADMIN的话显示里边的内容

4.sec:authorize="hasRole('ROLE_USER')表示当前用户角色为ROLE_USER的话显示该DIV里边的内容

#控制器

package org.cxzc.myyoung.springbootsecurity;                  import org.springframework.stereotype.Controller;              import org.springframework.ui.Model;              import org.springframework.web.bind.annotation.RequestMapping;                  @Controller              public class HomeController {              @RequestMapping("/")              public String index(Model model) {              Msg msg = new Msg("测试标题", "测试内容", "额外信息,只对管理员显示");              model.addAttribute("msg", msg);              return "index";              }              }           

该控制器比较简单,为了首页显示准备数据。

#运行

运行项目,浏览器中输入 http://localhost:8080/自动跳转到http://localhost:8080/login 展示一个登录界面,

Spring Boot(十四)Spring Boot中使用Security实现权限控制

下面分别输入 正确的账号 和 错误的账号,会有不同的结果信息展示。

ok,本篇内容到这里就完成了,如果小伙伴还有疑问,可以 关注 公众号 加群,我们一起进步

参考:

1. 《JavaEE开发的颠覆者 Spring Boot实战》

本案例下载地址:

https://github.com/ProceduralZC/itcxzc/tree/master/springbootsecurity

我的开源项目:

一点知识学院(Spring Boot开源项目)

程序职场 简介:。专注于 Spring Boot ,微服务,前端APP,副业赚钱,职场规划,运营管理 等,关注后回复   Java资料 ,领取为你精心准备的学习干货!

一个专门讲述 技术,赚钱,成长 的公号

一个执着的职场程序员

每天早八点为你准备精彩文章