1. 程式人生 > >SpringBoot整合Shiro思路以及程式碼過程

SpringBoot整合Shiro思路以及程式碼過程

模型 假設存在使用者(User)、角色(Role)、許可權(Permission)3中模型。依賴關係如下:使用者分配角色,角色分配許可權。使用者不直接參與許可權的分配。SpringBoot整合Shiro流程 demo的程式碼架構如下:

建立IO模型User存在:1、唯一ID 2、使用者名稱 3、密碼 4、擁有的Rolepublic class User {private Integer uid; private String username; private String password; private Set<Role> roles = new HashSet<>()
;}Role存在:1、唯一ID 2、角色名 3、角色擁有的許可權 4、擁有該角色的使用者(可以不需要)public class Role {private Integer rid; private String rname; private Set<Permission> permissions = new HashSet<>(); private Set<User> users = new HashSet<>();}Permission存在:1、唯一ID 2、許可權名 3、。。。public class Permission {
private Integer pid; private String name; private String url;}資料庫sql如下:-- 許可權表 --CREATE TABLE permission ( pid int(11) NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL DEFAULT '', url VARCHAR(255) DEFAULT '', PRIMARY KEY (pid)) ENGINE = InnoDB DEFAULT CHARSET = utf8;INSERT INTO permission VALUES ('1', 'add', '');INSERT INTO permission VALUES ('2', 'delete', '');INSERT INTO permission VALUES ('3', 'edit', '');INSERT INTO permission VALUES ('4', 'query', '');-- 使用者表 --CREATE TABLE user( uid int(11) NOT NULL AUTO_INCREMENT, username VARCHAR(255) NOT NULL DEFAULT '', password VARCHAR(255) NOT NULL DEFAULT '', PRIMARY KEY (uid)) ENGINE = InnoDB DEFAULT CHARSET = utf8;INSERT INTO user VALUES ('1', 'admin', '123');INSERT INTO user VALUES ('2', 'demo', '123');-- 角色表 --CREATE TABLE role( rid int(11) NOT NULL AUTO_INCREMENT, rname VARCHAR(255) NOT NULL DEFAULT '', PRIMARY KEY (rid)) ENGINE = InnoDB DEFAULT CHARSET = utf8;INSERT INTO role VALUES ('1', 'admin');INSERT INTO role VALUES ('2', 'customer');-- 許可權角色關係表 --CREATE TABLE permission_role ( rid int(11) NOT NULL , pid int(11) NOT NULL , KEY idx_rid (rid), KEY idx_pid (pid)) ENGINE = InnoDB DEFAULT CHARSET = utf8;INSERT INTO permission_role VALUES ('1', '1');INSERT INTO permission_role VALUES ('1', '2');INSERT INTO permission_role VALUES ('1', '3');INSERT INTO permission_role VALUES ('1', '4');INSERT INTO permission_role VALUES ('2', '1');INSERT INTO permission_role VALUES ('2', '4');-- 使用者角色關係表 --CREATE TABLE user_role ( uid int(11) NOT NULL , rid int(11) NOT NULL , KEY idx_uid (uid), KEY idx_rid (rid)) ENGINE = InnoDB DEFAULT CHARSET = utf8;INSERT INTO user_role VALUES (1, 1);INSERT INTO user_role VALUES (2, 2);Mapper的配置
1、UserMapper根據使用者名稱去資料庫查詢實體public interface UserMapper { User findByUsername(@Param("username") String username);}2、service配置存在如下關係


3、mapper.xmlmapper中配置好各個IO的對應情況

需要配置讀取UserMapper.xml的路徑

application中需要配置需要載入的mapper類路徑

授權與鑑權需要繼承 import org.apache.shiro.realm.AuthorizingRealm; 實現當中的方法。

1、第一個方法為授權2、第二個方法為登陸1、授權:核心思想:
  • 獲取當前使用者資訊
  • 因為user存放的是set<Role>,所以用for迴圈取出內容
  • 取出的role存放new 出來的List中
  • 利用for迴圈取出permission放入new出來的List中
  • 將剛才的list放入new SimpleAuthorizationInfo() 中的role和permission中
  • 返回該物件
@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){// 獲取User使用者User user = (User) principals.fromRealm(this.getClass().getName()).iterator().next();List<String> permissionList = new ArrayList<>();List<String> roleNameList = new ArrayList<>();Set<Role> roleSet = user.getRoles(); if (roleSet != null) {for (Role role : roleSet) { roleNameList.add(role.getRname());Set<Permission> permissionSet = role.getPermissions(); if (permissionSet != null) {for (Permission permission : permissionSet) { permissionList.add(permission.getName());} } } }// 需要把角色和許可權放入infoSimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// 許可權設定info.addStringPermissions(permissionList);// 角色設定info.addRoles(roleNameList); return info;}1、登陸:核心思想:
  • token中獲取當前使用者資訊
  • 因為user存放的是set<Role>,所以用for迴圈取出內容
  • 取出使用者名稱。使用者名稱和密碼是byte存放,可以考慮用new String轉換。
  • 返回SimpleAuthenticationInfo物件。包括使用者實體,密碼,該物件名
@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException{ UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;String username = usernamePasswordToken.getUsername();User user = userService.findByUsername(username); return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());}校驗重寫設定繼承SimpleCredentialsMatcher重寫校驗方法校驗方法可以自己設定,例如:加密鹽(具體需要網上看教程)這裡只是做簡單的對比並且返回對比結果。public class CredentialMatcher extends SimpleCredentialsMatcher{@Overridepublic boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;String password = new String(usernamePasswordToken.getPassword());String dbPassword = (String) info.getCredentials(); return this.equals(password, dbPassword);}}ShiroConfiguration的配置@Configurationpublic class ShiroConfiguration{@Bean("shiroFilter")public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();bean.setSecurityManager(manager);// 登陸介面bean.setLoginUrl("/login");// 成功登陸後的介面bean.setSuccessUrl("/index");// 沒有許可權訪問的介面bean.setUnauthorizedUrl("/unauthorized");// 定製相關表單是否需要相關許可權的設定,具體配置資訊請看:Shiro-內建的FilterChainLinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); //注意過濾器配置順序 不能顛倒這裡是按照順序判斷的// index介面需要鑑權filterChainDefinitionMap.put("/index", "authc");// loginloginUser表單不需要驗證filterChainDefinitionMap.put("/login", "anon");filterChainDefinitionMap.put("/loginUser", "anon");// admin表單需要角色 admin 才能訪問filterChainDefinitionMap.put("/admin", "roles[admin]");// edit表單需要許可權 edit 才能訪問filterChainDefinitionMap.put("/edit", "perms[edit]");filterChainDefinitionMap.put("/druid/**", "anon");filterChainDefinitionMap.put("/**", "user");bean.setFilterChainDefinitionMap(filterChainDefinitionMap); return bean;}@Bean("securityManager")public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager();manager.setRealm(authRealm); return manager;}@Bean("authRealm")public AuthRealm authRealm() { AuthRealm authRealm = new AuthRealm();/** * shiro自帶的MemoryConstrainedCacheManager作快取只能用於本機,那麼在叢集時就無法使用,* 如果使用ehcacheredis等其他快取,可以參考https://www.cnblogs.com/lic309/p/4072848.html */authRealm.setCacheManager(new MemoryConstrainedCacheManager());// com.mmall.demo2.CredentialMatcher中自定義的密碼比較器對密碼進行比較authRealm.setCredentialsMatcher(new CredentialMatcher()); return authRealm;}// shirospring進行繫結@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(securityManager); return advisor;}// 開啟自動程式碼,設定為true即可@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();creator.setProxyTargetClass(true); return creator;}}其他程式碼展示Controller程式碼@Controllerpublic class TestController{@RequestMapping("login")public String login() {return "login";}@RequestMapping("/index")public String index() {return "index";}@RequestMapping("/logout")public String logout() {// 先驗證主體Subject subject = SecurityUtils.getSubject(); if (subject != null) { subject.logout();}return "login";}@RequestMapping("unauthorized")public String unauthorized() {return "unauthorized";}@RequestMapping(