springBoot 2.0.3 + SpringSecurity 5.0.6 + thymeleaf + boostrap 權限管理案例

1、 工於成其實,必先搭建springboot工程,配置我們pom.xml 所需的jar依賴         

<!-- thymeleaf 模板依赖 -->

              <dependency>

                     <groupId>org.springframework.boot</groupId>

                     <artifactId>spring-boot-starter-thymeleaf</artifactId>

              </dependency>

              <!-- springSecurity 权限控制依赖 -->

              <dependency>

                     <groupId>org.springframework.boot</groupId>

                     <artifactId>spring-boot-starter-security</artifactId>

              </dependency>

              <!-- thymeleaf-extras-springsecurity4 該jar必須手動引入 -->

        <dependency>

            <groupId>org.thymeleaf.extras</groupId>

            <artifactId>thymeleaf-extras-springsecurity4</artifactId>

            <version>3.0.2.RELEASE</version><!--$NO-MVN-MAN-VER$-->

        </dependency>

              <!-- mysql數據庫 -->

        <dependency>

               <groupId>mysql</groupId>

               <artifactId>mysql-connector-java</artifactId>

               <scope>runtime</scope>

        </dependency>

       <!-- 引入 jpa.jar --><dependency<groupId>org.springframework.boot</groupId <artifactId>spring-boot-starter-data-jpa</artifactId></dependency>

2、對我們 Application.yml 配置,整個項目環境

spring:

  thymeleaf:

    encoding: UTF-8

    cache: false #热部署静态文件,禁止缓存

    mode: HTML5 #使用HTML5标准

#配置数据源   

  datasource:

    username: root

    password: '123456'

    url: jdbc:mysql://127.0.0.1:3306/springsecurityStudying?characterEncoding=utf-8&useSSL=false                                                        

    driver-class-name: com.mysql.jdbc.Driver

  jpa:

    hibernate:

      ddl-auto: update #自动更新建表

    show-sql: true

    database-platform: org.hibernate.dialect.MySQLDialect # 配置數據庫方言

3、開始編寫我們的所需的SQL脚本

SET FOREIGN_KEY_CHECKS=0;

DROP TABLE IF EXISTS `authority`;

CREATE TABLE `authority` (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,

  `auth_Name` varchar(32) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `authority` VALUES ('1', 'ADMIN');

INSERT INTO `authority` VALUES ('2', 'MANAGER');

INSERT INTO `authority` VALUES ('3', 'PRESIDENT');

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,

  `user_name` varchar(32) NOT NULL,

  `pass_word` varchar(99) NOT NULL,

  `email` varchar(50) DEFAULT NULL,

  PRIMARY KEY (`id`),

  UNIQUE KEY `user_name` (`user_name`)

) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES ('1', 'baihoo', '$2a$10$N7ME1n6kScoF3NkNaICqFuD2anQpOanTxDiWXIF9qjsgtWnCTXLsi', '[email protected]');

INSERT INTO `user` VALUES ('2', 'baihoo.god', '$2a$10$N7ME1n6kScoF3NkNaICqFuD2anQpOanTxDiWXIF9qjsgtWnCTXLsi', '[email protected]');

INSERT INTO `user` VALUES ('3', 'baihoo.chen', '$2a$10$N7ME1n6kScoF3NkNaICqFuD2anQpOanTxDiWXIF9qjsgtWnCTXLsi', '[email protected]');

INSERT INTO `user` VALUES ('5', 'baiHoo2', '$2a$10$pPreldvox9oX/haR.ugUjuZi8nmLXjcECfEX6BPFPxbIPTvGxAsjG', '[email protected]');

DROP TABLE IF EXISTS `user_authority`;

CREATE TABLE `user_authority` (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,

  `user_id` bigint(20) DEFAULT NULL,

  `authority_id` bigint(20) DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `user_id` (`user_id`),

  KEY `authority_id` (`authority_id`),

  CONSTRAINT `user_authority_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,

  CONSTRAINT `user_authority_ibfk_2` FOREIGN KEY (`authority_id`) REFERENCES `authority` (`id`) ON DELETE CASCADE ON UPDATE CASCADE

) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

INSERT INTO `user_authority` VALUES ('1', '1', '1');

INSERT INTO `user_authority` VALUES ('2', '1', '2');

INSERT INTO `user_authority` VALUES ('3', '2', '2');

INSERT INTO `user_authority` VALUES ('4', '2', '3');

INSERT INTO `user_authority` VALUES ('5', '3', '1');

INSERT INTO `user_authority` VALUES ('6', '2', '2');

4、熟悉MVC三層架構的小夥伴們,開始編寫我們domain曾實體代碼

/**

 * 用戶授權角色類

 * @author Administrator

 *

 */

@Entity(name="Authority")

public class Authority  implements GrantedAuthority , Serializable{                                                                                                          

         @Id @GeneratedValue(strategy=GenerationType.IDENTITY)  private Long id;

         @Size(min = 2, max = 32) @Column(name="auth_name" , nullable = false, length = 20) // 映射为字段,值不能为空                    

         private String authName;

         public Authority() {

                   super();

         }

         @Override

         public String toString() {

                   return "Authority [id=" + id + ", authName=" + authName + "]";

         }

         public Authority(Long id, String authName) {

                   super();

                   this.id = id;

                   this.authName = authName;

         }

         public Long getId() {

                   return id;

         }

         public void setId(Long id) {

                   this.id = id;

         }

         public String getAuthName() {

                   return authName;

         }

         public void setAuthName(String authName) {

                   this.authName = authName;

         }

         @Override

         public String getAuthority() {

                   //權限名稱

                   return authName;

         }

}

/**

 * 用户实体

 *

 * @author Administrator

 *

 */

@Entity(name="user") // 實體

public class User implements UserDetails, Serializable {

         @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // 自動增長

         private Long id; // 实体一个唯一标识

         @Size(min = 2, max = 32) @Column(name="user_name" , nullable = false, length = 20) // 映射为字段,值不能为空                    

         private String username;

         @Size(max = 99) @Column(name="pass_word" , length = 99)

         private String password;

         @Size(max = 50) @Email

         @Column(nullable = false, length = 50, unique = true)

         private String email;

         @ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)

         /**

          * 加入中間表user_authority

          *              中間表加入列user_id,參考列為當前主鍵列

          *              中間表加入列authority_id, 參考當前表倒置到Authority表的主鍵列

          */

         @JoinTable(name = "user_authority",

                                                        joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),

                                                        inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id"))

    private List<Authority> authorities;

         public User() {

         }

         public User(Long id, String username, String password, String email) {

                   super();

                   this.id = id;

                   this.username = username;

                   this.password = password;

                   this.email = email;

         }

         public Long getId() {

                   return id;

         }

         public void setId(Long id) {

                   this.id = id;

         }

         public String getUsername() {

                   return username;

         }

         public void setUsername(String username) {

                   this.username = username;

         

         public String getPassword() {

                   return password;

         }

         /**

          * 密碼BCrypt加密

          * @param password

          */

         public void setPassword(String password) {

        PasswordEncoder  encoder = new BCryptPasswordEncoder();

        String encodePasswd = encoder.encode(password);

        this.password = encodePasswd;

         }

         public String getEmail() {

                   return email;

         }

         public void setEmail(String email) {

                   this.email = email;

         }

         /**

          * 需将 List<Authority> 转成 List<SimpleGrantedAuthority>,否则前端拿不到角色列表名称

          */

         @Override

         public Collection<? extends GrantedAuthority> getAuthorities() {

        List<SimpleGrantedAuthority> simpleAuthorities = new ArrayList<>();

        for(GrantedAuthority authority : this.authorities){

            simpleAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));

        }

        return simpleAuthorities;

         }

         @Override

         public boolean isAccountNonExpired() {

                   //重載默認是false,我們要改成true

                   return true;

         }

         @Override

         public boolean isAccountNonLocked() {

                   //重載默認是false,我們要改成true

                   return true;

         }

         @Override

         public boolean isCredentialsNonExpired() {

                   //重載默認是false,我們要改成true

                   return true;

         }

         @Override

         public boolean isEnabled() {

                   //重載默認是false,我們要改成true

                   return true;

         }

         @Override

         public String toString() {

                   return "User [id=" + id + ", username=" + username + ", password=" + password + ", email=" + email

                                     + ", authorities=" + authorities + "]";

         }

}

編寫我們repository層的代碼

/**

 * 實現JPA接口類

 * @author Administrator

 *

 */

public interface AuthorityRepository extends JpaRepository<Authority, Long>{                                                                                          

}

/**

 * UserRepository 接口

 * @author Administrator

 *

 */

public interface UserRepository  extends JpaRepository<User, Long>{                                                                                                    

              /**

               * 通過名稱查詢用戶

               * @param username

               * @return

               */

              public User findByUsername(String username);

              /**

               * 通過用戶名和密碼查詢用戶

               * @param username

               * @param password

               * @return

               */

              public User findByUsernameAndPassword(String username , String password);

}

 編寫我們service層的代碼

/**

 *

 * UserService 服務層<br>

 * UserService 實現 UserDetailsService 接口,重寫其方法!這是必須<br>

 *

 * @author Administrator

 *

 */

@Service("userservice")

@SuppressWarnings("all")

public class UserService implements UserDetailsService{                                                                                                                           

         @Autowired

         UserRepository userRepository;     

         @Override

         public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

                   User user = userRepository.findByUsername(username);

                   if(user == null ) {

                            throw new UsernameNotFoundException("用户名不存在");

                   }

                   Boolean locked = user.isAccountNonLocked();               

                   return user;

         }

         public User findByUsernameAndPassword(String username , String password) {

                   return userRepository.findByUsernameAndPassword(username, password);

         }

}

/**

 *

 * @author Administrator

 *

 */

public class AuthorityService {                                                                                                                                                                   

}

 編寫我們controller層的代碼

/**

 * 主頁控制器

 * @author Administrator

 *

 */

@Controller

public class MainController {                                                                                                                                                                      

         @Autowired

         @Qualifier("userRepository")

         private UserRepository userRepository;

         /**

          * 根目錄控制

          * @return

          */

         @GetMapping("/")

         public String root() {

                   return "redirect:/index";

         }

         /**

          * 網站首頁

          * @return

          */

         @GetMapping("/index")

         public String index() {

                   return "index"; //index.html

         }

         /**

          * 登陸界面

          * @return

          */

         @GetMapping("/login")

         public String login() {

                   return "login"; //login.html

         }

         /**

          * 403錯誤界面

          * @return

          */

         @GetMapping("/403")

    public String error403() {

        return "/error/403";

    }

         /**

          * 登陸錯誤,返回登陸頁面,并添加錯誤信息

          * @param model

          * @return

          */

         @GetMapping("/login-error")

         public String loginError(Model model , HttpSession session , @RequestParam(value = "secError", required = true) Boolean secError) {

                   model.addAttribute("loginError" , true);

                   //獲取其service層獲取登陸用戶抛出的異常信息

                   Exception exception = (Exception)session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");

                   model.addAttribute("errorMessage" ,exception.getMessage());

                   return "login";

         }

}

/**

 * 用户控制层

 *

 * @author Administrator

 *

 */

@RestController

@RequestMapping("/user")

public class UserController {                                                                                                                                                                        

         @Autowired

         @Qualifier("userRepository")

         private UserRepository userRepository;

         /**

          * 页面获取用户列表

          *

          * @param model

          * @return

          */

         @GetMapping("/list")

         public ModelAndView list(Model model) {

                   model.addAttribute("userList", userRepository.findAll());

                   model.addAttribute("title", "用户管理");

                   return new ModelAndView("users/list", "userModel", model);

         }

         /**

          * 根据id查询用户并页面展示

          *

          * @param id

          * @param model

          * @return

          */

         @GetMapping("/view/{id}")

         public ModelAndView view(@PathVariable("id") Long id, Model model) {

                   Optional<User> userOp = userRepository.findById(id);

                   model.addAttribute("user", userOp.get());

                   model.addAttribute("title", "查看用户");

                   return new ModelAndView("users/view", "userModel", model);

         }

         /**

          * 获取创建表单页面

          *

          * @param model

          * @return

          */

         @GetMapping("/form")

         public ModelAndView createForm(Model model) {

                   model.addAttribute("user", new User());

                   model.addAttribute("title", "创建用户");

                   return new ModelAndView("users/form", "userModel", model);

         }

         /**

          * 保存用戶

          * @param user

          * @return

          */

         @PostMapping("/submit")

         public ModelAndView saveOrUpdateUser(User user) {

                   user = userRepository.save(user);

                   ModelAndView mav = new ModelAndView();

                   mav.setViewName("redirect:list");// 重定向至list映射方法

                   return mav;

         }

         /**

          * 根据id查詢用戶帶參并跳轉到form頁面

          *

          * @param id

          * @param model

          * @return

          */

         @GetMapping("/modify/{id}")

         public ModelAndView modifyUser(@PathVariable("id") Long id, Model model) {

                   Optional<User> userOp = userRepository.findById(id);

                   model.addAttribute("user", userOp.get());

                   model.addAttribute("title", "修改用户");

                   return new ModelAndView("users/form", "userModel", model);

         }

         /**

          * 根据id刪除用戶

          *

          * @param id

          * @param model

          * @return

          */

         @GetMapping("/delete/{id}")

         public ModelAndView deleteUser(@PathVariable("id") Long id, Model model) {

                   userRepository.deleteById(id);

                   ModelAndView mav = new ModelAndView();

                   mav.setViewName("redirect:/user/list");// 重定向至list映射方法

                   return mav;

         }

}

 既然要做權限控制,那麽我們肯定就要編寫springSecurity配置類

/**

 * springSecurity安全配置类

 *              注意:該類上的注解包含"@Configuration"因此只會被初始化加載

 *

 *              springSecurity5.0.0以後角色是角色,權限是權限,兩者不能混爲一談

 *

 * @author Administrator

 *

 */

@EnableWebSecurity // 配置注解,啓動web認證安全

//@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用方法级别的权限认证

public class SecurityConfig extends WebSecurityConfigurerAdapter {                                                                                                              

         @Override

         protected void configure(HttpSecurity http) throws Exception {

                   //  允许所有用户访问"/bootstrap/**"和"/index"

                   http.authorizeRequests()

                                     .antMatchers("/bootstrap/css/**", "/bootstrap/js/**", "/bootstrap/fonts/**", "/").permitAll()// 都可以訪問

                                     .antMatchers("/user/**").hasAnyAuthority("ADMIN")                                                                                                                                         // 需要相應的授權才能訪問

                                     .and().formLogin()                                                                                                                                                                                                                                                // 基於form表單登陸驗證

                                     .loginPage("/login").failureUrl("/login-error?secError=true")                                                                                          // 若用戶錯誤,則跳轉自定義的登陸界面

//                                 .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler())                        // 处理异常,handler方式,拒绝访问就重定向到 403 页面

                                     .and().exceptionHandling().accessDeniedPage("/403")                                                                                                      // 处理异常,拒绝访问就重定向到 403 页面

                                     ;

         }

         /**

          *

          */

         @Override

         public void configure(AuthenticationManagerBuilder auth) throws Exception {

                   auth.userDetailsService(userService());

                   auth.authenticationProvider(authenticationProvider());

                  

//               若要方便與測試那麽就要和passwordEncoder() 返回的 passwordEncoder() 實現類前呼後應 。認證信息儲存與内存中

//               auth.inMemoryAuthentication()

//               .withUser("baihoo").password("12345").roles("ADMIN");

         }

         @Bean

         public PasswordEncoder passwordEncoder() {

                   return new BCryptPasswordEncoder(); // 使用 BCrypt 加密,注意:原生密碼也得采用這個加密類加密

//               return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();

         }

         @Bean

         public UserService userService() {

                   return new UserService();

         }

         @Bean

         public AuthenticationProvider authenticationProvider() {

                   DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();

//               UserService 繼承UserDetailsService,實現其 loadUserByUsername() 方法。

                   authenticationProvider.setUserDetailsService(userService());

//               设置密码加密方式

                   authenticationProvider.setPasswordEncoder(passwordEncoder());

                   return authenticationProvider;

         }

         @Bean

         public AccessDeniedHandler accessDeniedHandler() {

                   return new MyAccessDeniedHandler();

         }

}

注意:springSecurity5.0.0以後角色是角色,權限是權限,兩者不能混爲一談,這可是小編我遇到第一個坑

自定義拒絕訪問handler,小編我本來是可以不寫,對整個案例工程沒什麽影響, 好學小夥伴可以看看,寫的不好多多見諒!

/**

 * 定义403无权限访问的处理,重定向到/403页面

 *

 * @author Administrator

 *

 */

public class MyAccessDeniedHandler implements AccessDeniedHandler {                                                                                                    

         private static Logger logger = LoggerFactory.getLogger(MyAccessDeniedHandler.class);

         @Override

         public void handle(HttpServletRequest request, HttpServletResponse response,

                            AccessDeniedException accessDeniedException) throws IOException, ServletException {

                   Authentication auth = SecurityContextHolder.getContext().getAuthentication();

                   if (auth != null) {

                            logger.info("用戶: '" + auth.getName() + "'試圖訪問受保護的 URL: "

                                               + request.getRequestURI());

                   }

                   response.sendRedirect(request.getContextPath() + "/403");

         }

}

 5、著手開始編寫我們前端html代碼!

該目錄下/resources/templates/fragments/ 著手編寫header.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

         xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"

         xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"

         th:fragment="header">

<head>

         <meta charset="UTF-8">

    <meta name="viewport"

          content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

<title>bootsrap in action</title>

<link href="../../static/bootstrap/css/tether.min.css"

         th:href="@{/bootstrap/css/tether.min.css}" rel="stylesheet">

<!-- bootstrap css样式 -->

<link href="../../static/bootstrap/css/bootstrap.min.css"

         th:href="@{/bootstrap/css/bootstrap.min.css}" rel="stylesheet">

<!-- 样式文字css样式 -->

<link href="../../static/bootstrap/css/font-awesome.min.css" th:href="@{/bootstrap/css/font-awesome.min.css}"

         rel="stylesheet">

<link href="../../static/bootstrap/css/nprogress.css" th:href="@{/bootstrap/css/nprogress.css}"

         rel="stylesheet">

<link href="../../static/bootstrap/css/thinker-md.vendor.css" th:href="@{/bootstrap/css/thinker-md.vendor.css}"

         rel="stylesheet">

<link href="../../static/bootstrap/css/bootstrap-tagsinput.css" th:href="@{/bootstrap/css/bootstrap-tagsinput.css}"

         rel="stylesheet">

<link href="../../static/bootstrap/css/component-chosen.min.css" th:href="@{/bootstrap/css/component-chosen.min.css}"

         rel="stylesheet">

<link href="../../static/bootstrap/css/toastr.min.css" th:href="@{/bootstrap/css/toastr.min.css}"

         rel="stylesheet">

<!-- 图片编辑的css -->

<link href="../../static/bootstrap/css/cropbox.css" th:href="@{/bootstrap/css/cropbox.css}"

         rel="stylesheet">

<!-- 自定义的样式 -->

<link href="../../static/bootstrap/css/style.css" th:href="@{/bootstrap/css/style.css}"

         rel="stylesheet">

<link href="../../static/bootstrap/css/thymeleaf-bootstrap-paginator.css" th:href="@{/bootstrap/css/thymeleaf-bootstrap-paginator.css}"

         rel="stylesheet">

<link href="../../static/bootstrap/css/blog.css" th:href="@{/bootstrap/css/blog.css}"

         rel="stylesheet">

</head>

<body>

         <nav class="navbar navbar-inverse bg-inverse navbar-toggleable-md">

                   <div class="container">

                            <button class="navbar-toggler navbar-toggler-right" type="button"

                                     data-toggle="collapse" data-target="#navbarsContainer">

                                     <span class="navbar-toggler-icon"></span>

                            </button>

                            <a class="navbar-brand" href="/" th:href="@{~/}">baiHoo Blog</a>

                            <div class="collapse navbar-collapse" id="navbarsContainer">

                                     <ul class="navbar-nav mr-auto">

                                               <li class="nav-item">

                                                        <!-- @{~/user} 相对于服务器下面 --> <a class="nav-link"

                                                        th:href="@{~/}">首页<span class="sr-only">(current)</span></a>

                                               </li>

                                     </ul>

                                     <!--

                                               曲義解釋:

                                                        授權認證--已認證,并证明是真实的、可靠的。用戶已登陸 -->

                                     <!-- 登陸判斷 -->

                                     <div sec:authorize="isAuthenticated()" class="row">

                                               <ul class="navbar-nav mr-auto">

                                                        <li class="nav-item">

                                                                 <span class="nav-link" sec:authentication="name"></span>

                                                        </li>

                                               </ul>

                                               <form action="/logout" th:action="@{~/logout}" method="post">

                                                        <!--

                                                        logout在我編寫的controller是沒有的,該logout遵循springSecurity本身規則的,注銷用戶

                                                         -->

                                                        <input class="btn btn-outline-success" type="submit" value="退出">

                                               </form>

                                     </div>

                                     <!--

                                               曲義解釋:

                                                        授權認證--未認證,匿名未登陸的

                                      -->

                                     <div sec:authorize="isAnonymous()">

                                               <a href="/login" th:href="@{~/login}" class="btn btn-outline-success my-2 my-sm-0" type="submit">登陸</a>

                                     </div>

                            </div>

                   </div>

         </nav>

</body>

</html>

該目錄下/resources/templates/fragments/ 著手編寫footer.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">

<head>

         <meta charset="UTF-8">                                                                                                                                                                    

</head>

<body>

         <footer class="blog-footer bg-inverse" data-th-fragment="footer" th:fragment="footer">

                   <!--

                   <a id="goToTop" href="#">

                            <i class="fa fa-chevron-up fa-3x" aria-hidden="true"></i>

                   </a>

                    -->

             <div class="container">

                           <p class="m-0 text-center text-white">© 2018 <a href="https://baihoo.com">baihoo.com</a></p>

             </div>

               <!-- JavaScript -->

             <script src="../../static/bootstrap/js/jquery-3.1.1.min.js" th:src="@{/bootstrap/js/jquery-3.1.1.min.js}"></script>

             <script src="../../static/bootstrap/js/jquery.form.min.js" th:src="@{/bootstrap/js/jquery.form.min.js}"></script>

             <script src="../../static/bootstrap/js/tether.min.js" th:src="@{/bootstrap/js/tether.min.js}"></script>

             <script src="../../static/bootstrap/js/bootstrap.min.js" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>

             <script src="../../static/bootstrap/js/nprogress.js" th:src="@{/bootstrap/js/nprogress.js}"></script>

             <script src="../../static/bootstrap/js/thinker-md.vendor.min.js" th:src="@{/bootstrap/js/thinker-md.vendor.min.js}"></script>

             <script src="../../static/bootstrap/js/jquery.tag-editor.min.js" th:src="@{/bootstrap/js/jquery.tag-editor.min.js}"></script>

             <script src="../../static/bootstrap/js/chosen.jquery.js" th:src="@{/bootstrap/js/chosen.jquery.js}"></script>

             <script src="../../static/bootstrap/js/toastr.min.js" th:src="@{/bootstrap/js/toastr.min.js}"></script>

             <script src="../../static/bootstrap/js/cropbox.js" th:src="@{/bootstrap/js/cropbox.js}"></script>

             <script src="../../static/bootstrap/js/thymeleaf-bootstrap-paginator.js" th:src="@{/bootstrap/js/thymeleaf-bootstrap-paginator.js}"></script>

             <script src="../../static/bootstrap/js/catalog-generator.js" th:src="@{/bootstrap/js/catalog-generator.js}"></script>

             <script src="../../static/bootstrap/js/main.js" th:src="@{/bootstrap/js/main.js}"></script>

          </footer>

</body>

</html>

該目錄下/resources/templates/error/ 著手編寫403.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

       xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"

       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

<!-- thymeleaf模板集合springsecurity標簽權限控制,的命名空間 -->

<!-- 引用替换当前的头部信息html

       曲义解释:

              引用header.html 定义的 header片段

-->

<head th:replace="~{fragments/header :: header}">

<meta charset="UTF-8">

</head>

<body>

       <!-- page content -->

       <div class="container blog-content-container">

              <div class="starter-template">

                <h1>403 - 没有访问权限</h1><div th:inline="text">Sorry!  '[[${#httpServletRequest.remoteUser}]]', 你没有权限访问此页面.</div></div>

       </div>

       <div th:replace="~{fragments/footer :: footer}"></div>

</body>

</html>

 該目錄下/resources/users/error/ 編寫三個html文件

   form.tml

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">

<!-- 引用替换当前的头部信息html

         曲义解释:

                   引用header.html 定义的 header片段

-->

<head th:replace="~{fragments/header :: header}">

         <meta charset="UTF-8">

</head>

<body>

         <!-- page content -->

         <div class="container blog-content-container">

                   <h3 th:text="${userModel.title}">原型效果 baihoo</h3>

                   <!-- 获取userModel绑定user -->

                   <form action="/user/submit" th:action="@{/user/submit}" method="post"

                            th:object="${userModel.user}">

                            <input type="hidden" name="id" th:value="*{id}">

                            <!-- 直接取出当前对象属性的值 -->名称:<br> <input type="text" class="form-control" name="username" th:value="*{username}"><br>

                            <!-- 直接取出当前对象属性的值 -->密碼:<br> <input type="password" class="form-control" name="password" th:value="*{password}"><br>

                            <!-- 直接取出当前对象属性的值 -->邮箱:<br> <input type="text" class="form-control" name="email" th:value="*{email}"><br>

                            <!-- 直接取出当前对象属性的值 --><input type="submit" class="btn btn-default" value="提交">

                   </form>

         </div>

         <div th:replace="~{fragments/footer :: footer}"></div>

</body>

</html>

 list.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">

<!-- 引用替换当前的头部信息html

         曲义解释:

                   引用header.html 定义的 header片段

-->

<head th:replace="~{fragments/header :: header}">

         <meta charset="UTF-8">

</head>

<body>

         <!-- page content -->

         <div class="container blog-content-container">

                   <h3 th:text="${userModel.title}">原型效果 baihoo</h3>

                   <div>

                            <a class="btn btn-default" href="/user/form.html" th:href="@{/user/form}">创建用户</a>

                   </div>

                   <table class="table table-striped">

                            <thead><tr> <td>ID</td><td>Email</td><td>用户名</td> </tr></thead>

                            <tbody> <!-- 判断userModel.userList 是否没有值 --><tr th:if="${userModel.userList.size() eq 0}"> <td colspan="3">没有用户信息!</td></tr>

                                     <!-- th:each 迭代 -->

                                     <tr th:each="user : ${userModel.userList}">

                                               <td th:text="${user.id}"></td>

                                               <td th:text="${user.email}"></td>

                                               <td>

                                                        <!-- 带参数的连接 --> <a href="view/view.html"

                                                        th:href="@{'/user/view/'+${user.id}}" th:text="${user.username}"></a>

                                               </td>

                                     </tr>

                            </tbody>

                            <tfoot>

                                     <tr>

                                               <td></td>

                                               <td></td>

                                               <td></td>

                                     </tr>

                            </tfoot>

                   </table>

         </div>

         <div th:replace="~{fragments/footer :: footer}"></div>

</body>

</html>

view.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

         xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">

<!-- 引用替换当前的头部信息html

         曲义解释:

                   引用header.html 定义的 header片段

-->

<head th:replace="~{fragments/header :: header}">

<meta charset="UTF-8">

</head>

<body>

         <!-- page content -->

         <div class="container blog-content-container">

                   <h3 th:text="${userModel.title}">原型效果 baihoo</h3>

                   <div>

                            <p>

                                     <strong>Id:</strong>&nbsp;&nbsp;<span th:text="${userModel.user.id}"></span>

                            </p>

                            <p>

                                     <strong>name:</strong>&nbsp;&nbsp;<span  th:text="${userModel.user.username}"></span>

                            </p>

                            <p>

                                     <strong>email:</strong>&nbsp;&nbsp;<span th:text="${userModel.user.email}"></span>

                            </p>

                   </div>

                   <div>

                            <a th:href="@{'/user/modify/'+${userModel.user.id}}">修改用戶</a>&nbsp;&nbsp;  <a th:href="@{'/user/delete/'+${userModel.user.id}}">刪除用戶</a>

                   </div>

         </div>

         <div>

                   <div th:replace="~{fragments/footer :: footer}"></div>                                                                                                              

         </div>

</body>

</html>

  該目錄下/resources/編寫

index.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"

      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

      <!-- thymeleaf模板集合springsecurity標簽權限控制,的命名空間 -->

     

<!-- 引用替换当前的头部信息html

         曲义解释:

                   引用header.html 定义的 header片段

-->

<head th:replace="~{fragments/header :: header}">

         <meta charset="UTF-8">

</head>

<body>

         <!-- page content -->

         <div class="container blog-content-container">

                   <!--

                            曲義解釋:

                                     授權認證--已認證,并证明是真实的、可靠的。用戶已登陸 -->

                   <div sec:authorize="isAuthenticated()">

                            <p>已有用戶登陸</p <p>登陸用戶:<span sec:authentication="name"></span></p>                                                                          

                            <!-- principal:主要演员,主角; 表示顯示用戶角色 -->

                            <p>用戶角色:<span sec:authentication="principal.authorities"></span></p>

                   </div>

                   <!--

                            曲義解釋:

                                     授權認證--未認證,匿名未登陸的

                    -->

                   <div sec:authorize="isAnonymous()">

                            <p>用戶未登陸</p>

                   </div>

         </div>

         <div th:replace="~{fragments/footer :: footer}"></div>

</body>

</html>

 login.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org"

      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"

     

      >

      <!-- thymeleaf模板集合springsecurity標簽權限控制,的命名空間 -->

     

<!-- 引用替换当前的头部信息html

         曲义解释:

                   引用header.html 定义的 header片段

-->

<head th:replace="~{fragments/header :: header}">

         <meta charset="UTF-8">

</head>

<body>

         <!-- page content -->

         <div class="container blog-content-container">

                   <!--

                   login在我們編寫的controller中是只是做跳轉頁的url , 并不對登陸用戶做實際操作,該login遵循springSecurity本身規則的,登陸用戶

                    -->

                   <form action="/login" th:action="@{/login}" method="post">

                            <h2>請登陸</h2>

                            <div class="form-group col-md-5">

                                     <label for="username" class="col-form-label">賬號</label>

                                     <input type="text" class="form-control" placeholder="請輸入用戶名" maxlength="25" name="username" id="username">

                            </div>

                            <div class="form-group col-md-5">

                                     <label for="password" class="col-form-label">密碼</label>

                                     <input type="password" class="form-control" placeholder="請輸入密碼" maxlength="32" name="password" id="password">

                            </div>

                            <div class="form-group col-md-5">

                                     <input type="checkbox" name="remember-me"/>记住我 <br>

                            </div>

                            <div class="form-group col-md-5">

                                     <input class="btn btn-primary" type="submit" value="登陸">

                            </div>

                            <div class="col-md-5" th:if="${loginError}">

                                     <p class="blog-label-error" th:text="${errorMessage}"></p>

                            </div>

                   </form>

         </div>

         <div th:replace="~{fragments/footer :: footer}"></div>

</body>

</html>

6、 目前爲止,我們的工程代碼算是,交代完畢了,看下頁面效果!http://localhost:8080/index

沒有admin權限的用戶登陸

 若訪問http://localhost:8080/user/list,會抛出沒有權限操作!

 有admin權限的用戶登陸

若訪問http://localhost:8080/user/list, 直接允許訪問 

贅言:

我們整個的 springBoot 2.0.3 + SpringSecurity 5.0.6 + thymeleaf + boostrap 權限管理案例,算告一段落了,需要源碼的小夥伴,直接下載我的github源碼

https://github.com/ChenBaiHong/baihoo.SpringSecurityExample

猜你喜欢

转载自blog.csdn.net/baiHoo_chen/article/details/81428022
今日推荐