shiro權限認證及授權的執行流程


《一,認證》

1.先建兩個class文件

   一個寫 AuthRealm (授權與認證方法,並繼承) extends AuthorizingRealm  

獲取其默認方法doGetAuthorizationInfo(授權方法) doGetAuthenticationInfo(認證方法) 

                 一個寫PasswordMatcher(密碼驗證器,並繼承) extends SimpleCredentialsMatcher

獲取默認方法doCredentialsMatch 

2.在Action的登錄方法中 

         @Action("loginAction_login")//重頁面跳轉過來的路徑名

         public String login() throws Exception {

             //判斷用戶名是不是為空,如果是說明沒有登錄,跳轉到用戶登錄頁面

             if(UtilFuns.isEmpty(username)){

                    return "login";

             }

//1.SecurityUtils:是shiro的一個工具類。通過SecurityUtils獲取getSubject 得到一個返回值

             Subject subject = SecurityUtils.getSubject();

//3.根據邏輯2。new一個 UsernamePasswordToken,並傳上用戶名及密碼。把返回值傳給登入作為條件。

             UsernamePasswordToken token = new UsernamePasswordToken(username,password);

             

             try {

//2. subject的返回值里有兩個方法logout:登出 login:登入。這里我們使用登錄方法,通過方法我們可以看到需要一個返回值:AuthenticationToken的類型,又因為AuthenticationToken  是一個接口,所以我們使用他下面的UsernamePasswordToken 的實現類來寫(ps:查看方法:Ctrl+t),

                    subject.login(token);//當調用subject的登入方法時,會跳轉到認證的方法上。。。。。。。。。。

 

//4.在證方法中subject已經把獲取到了用戶,所以我們用subject.getPrincipal 可以獲取到登錄的用戶,Principal:他是在認證方法中的principal:主要對象(登錄的用戶,詳情看認證方法return的哪一步注釋)

                    User user = (User) subject.getPrincipal();

//5.把user用戶數據通過Session.put放在session值棧中。SysConstant.CURRENT_USER_INFO:是一個返回的值,在jsp頁面中可以接收到,也可以直接寫一個字符串讓頁面接收,返回的數據可以在頁面做回顯等功能

                    session.put(SysConstant.CURRENT_USER_INFO, user);

                    return SUCCESS;//以上全部都過了后,讓其訪問頁面數據

             } catch (Exception e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                    super.put("errorInfo", "您的用戶名或密碼錯誤"); //登錄頁面的錯誤信息提示

                    return "login";

             }

       }

       

       

       //退出

       @Action("loginAction_logout")

       public String logout(){

             session.remove(SysConstant.CURRENT_USER_INFO);       //刪除session

             SecurityUtils.getSubject().logout();   //調用登出方法

             return "logout";

       }

3.在認證方法中的doGetAuthenticationInfo

            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {

             // TODO Auto-generated method stub

             System.out.println("調用認證方法");

             UsernamePasswordToken token =(UsernamePasswordToken)arg0;//先將arg0強轉為UsernamePasswordToken類型

             final String username = token.getUsername();//通過token獲取到用戶名

             Specification<User> spec = new Specification<User>() {   //把username 設為查詢條件,查詢數據庫是否有這個用戶名

                    @Override

                    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

                           // TODO Auto-generated method stub

                           return cb.equal(root.get("username").as(String.class),username);

                    }

             };

             List<User> find = userServiceimpl.find(spec); //把spec 條件放到 查詢中查詢數據  查詢用戶名

             if(find!=null&& find.size()>0){  //判斷返回的結果不為空,及返回的數不小於0

                    User user = find.get(0); //通過索引獲取到返回值的第一個數中的數據

                    return new SimpleAuthenticationInfo(user, user.getPassword(), getName()) ;//這里如果上面的都成立后會return到密碼校驗哪里去

  /*   SimpleAuthenticationInfo:是doGetAuthenticationInfo的一個實現類,因為doGetAuthenticationInfo 是一個接口不能直接new  

       把返回值添加到條件中 //principal:主要對象(登錄的用戶) , credentials:密碼 ,realm的名字可以通過getName獲取類名作為區分 */

             }

             return null;

       }

 

4.在密碼檢驗中PasswordMatcher  

public class PasswordMatcher extends SimpleCredentialsMatcher {  //先實現一個接口SimpleCredentialsMatcher  獲取doCredentialsMatch的內部方法

       @Override

       public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

             

             System.out.println("調用了密碼對比器");

             UsernamePasswordToken utoken = (UsernamePasswordToken) token; 

           /*[把AuthenticationToken 中的token 裝換為AuthenticationToken 中的(ps:查看方法Ctrl+t)

           UsernamePasswordToken實現類 因為AuthenticationToken 是接口不能new數據],*/

             

             String pwd = new String(utoken.getPassword());//通過utoken 獲取用戶密碼,並轉換成String類型,注意這里的轉換不能強轉,要用new的方法

             //source:要加密的內容   salt:增加復雜度的內容  哈希次數:2

             Md5Hash md5Hash = new Md5Hash(pwd, utoken.getUsername(), 2);  //調用Md5加密 為輸入的數據加密

             String credentials = (String)info.getCredentials();  //通過AuthenticationInfo 的info 查詢數據庫的密碼 裝換成String類型

             return equals(md5Hash.toString(),credentials); //對比用戶輸入的數據和數據庫密碼是否一致。return走,返回到Action方法中。

       }

}

 

5.執行流程圖

《二,授權》

1.在授權方法中

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("授權");

SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();

Set<String> permissionSet = new HashSet<>();
Set<String> roleNameSet = new HashSet<>();

ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal();
List<Integer> roleList = shiroUser.getRoleList();

for (Integer roleId : roleList) {
List<String> permissions = roleMenuMapper.findPermissionsByRoleId(roleId);
if (permissions != null) {
for (String permission : permissions) {
if (StringUtils.isNotEmpty(permission)) {
permissionSet.add(permission);
}
}
}
String roleName = roleMapper.findRoleNameByRoleId(roleId);
roleNameSet.add(roleName);
}

simpleAuthorizationInfo.addStringPermissions(permissionSet);
simpleAuthorizationInfo.addRoles(roleNameSet);
//查詢登錄用戶的所有角色的權限

return simpleAuthorizationInfo;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM