springBoot 2.0.3 + SpringSecurity 5.0.6 + thymeleaf + boostrap 許可權管理案例
1、 工於成其實,必先搭建springboot工程,配置我們pom.xml 所需的jar依賴
<!-- thymeleaf 模板依賴 --> <dependency> < <artifactId>spring-boot-starter-thymeleaf</artifactId> </ <!-- springSecurity 許可權控制依賴 --> <dependency> < <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"因此只會被初始化載入< |