java使用shiro小記

來源:互聯網
上載者:User

標籤:技術分享   static   subject   機器   set   資料   ons   man   logout   

1、架構

hiro是一個強大的簡單易用的Java安全架構,主要用來更便捷的認證,授權,加密,會話管理。Shiro首要的和最重要的目標就是容易使用並且容易理解。

Shiro是一個有許多特性的全面的安全架構,下面這幅圖可以瞭解Shiro的特性:

 

 

可以看出shiro除了基本的認證,授權,會話管理,加密之外,還有許多額外的特性。

從大的角度來看,Shiro有三個主要的概念:SubjectSecurityManagerRealms,下面這幅圖可以看到這些原件之間的互動。

Subject主體,代表了當前“使用者”,這個使用者不一定是一個具體的人,與當前應用互動的任何東西都是Subject,如網路爬蟲,機器人等;即一個抽象概念;所有Subject都綁定到SecurityManager,與Subject的所有互動都會委託給SecurityManager;可以把Subject認為是一個門面;SecurityManager才是實際的執行者;

SecurityManager安全管理器;即所有與安全有關的操作都會與SecurityManager互動;且它管理著所有Subject;可以看出它是Shiro的核心,它負責與後邊介紹的其他組件進行互動,如果學習過SpringMVC,你可以把它看成DispatcherServlet前端控制器;

Realm域,Shiro從從Realm擷取安全資料(如使用者、角色、許可權),就是說SecurityManager要驗證使用者身份,那麼它需要從Realm擷取相應的使用者進行比較以確定使用者身份是否合法;也需要從Realm得到使用者相應的角色/許可權進行驗證使用者是否能進行操作;可以把Realm看成DataSource,即安全資料來源。

2、名詞解釋:

Authentication身份認證/登入,驗證使用者是不是擁有相應的身份;

Authorization授權,即許可權驗證,驗證某個已認證的使用者是否擁有某個許可權;即判斷使用者是否能做事情,常見的如:驗證某個使用者是否擁有某個角色。或者細粒度的驗證某個使用者對某個資源是否具有某個許可權;

Session Manager會話管理,即使用者登入後就是一次會話,在沒有退出之前,它的所有資訊都在會話中;會話可以是普通JavaSE環境的,也可以是如Web環境的;

Cryptography加密,保護資料的安全性,如密碼加密儲存到資料庫,而不是明文儲存;

Web SupportWeb支援,可以非常容易的整合到Web環境;

Caching:緩衝,比如使用者登入後,其使用者資訊、擁有的角色/許可權不必每次去查,這樣可以提高效率;

Concurrencyshiro支援多線程應用的並發驗證,即如在一個線程中開啟另一個線程,能把許可權自動傳播過去;

Testing提供測試支援;

Run As允許一個使用者假裝為另一個使用者(如果他們允許)的身份進行訪問;

Remember Me記住我,這個是非常常見的功能,即一次登入後,下次再來的話不用登入了。

 

記住一點,Shiro不會去維護使用者、維護許可權;這些需要我們自己去設計/提供;然後通過相應的介面注入給Shiro即可。

3、主要代碼

public class ShiroDbRealm extends AuthorizingRealm {    private static final Logger LOGGER = LogManager.getLogger(ShiroDbRealm.class);    @Autowired    private UserService userService;    @Autowired    private IRoleService roleService;        public ShiroDbRealm(CacheManager cacheManager, CredentialsMatcher matcher) {        super(cacheManager, matcher);    }        /**     * Shiro登入認證     * 使用者登陸時執行     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {        LOGGER.info("Shiro開始登入認證");        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;        UserVO user = userService.queryByLoginName(token.getUsername());        // 帳號不存在        if (user == null) {            return null;        }        // 帳號未啟用        if (user.getStatus() == 1) {            return null;        }        // 讀取使用者的url和角色        Map<String, Set<String>> resourceMap = roleService.selectResourceMapByUserId(user.getId());        Set<String> urls = resourceMap.get("urls");        Set<String> roles = resourceMap.get("roles");        ShiroUser shiroUser = new ShiroUser(user.getId(), user.getLoginName(), user.getName(), urls);        shiroUser.setRoles(roles);        // 認證緩衝資訊        return new SimpleAuthenticationInfo(shiroUser, user.getPassword().toCharArray(), getName());    }    /**     * Shiro許可權認證     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        info.setRoles(shiroUser.getRoles());        info.addStringPermissions(shiroUser.getUrlSet());                return info;    }        @Override    public void onLogout(PrincipalCollection principals) {        super.clearCachedAuthorizationInfo(principals);        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();        removeUserCache(shiroUser);    }    /**     * 清除使用者緩衝     * @param shiroUser     */    public void removeUserCache(ShiroUser shiroUser){        removeUserCache(shiroUser.getLoginName());    }    /**     * 清除使用者緩衝     * @param loginName     */    public void removeUserCache(String loginName){        SimplePrincipalCollection principals = new SimplePrincipalCollection();        principals.add(loginName, super.getName());        super.clearCachedAuthenticationInfo(principals);    }}

  登陸的代碼為:

@PostMapping("/login")    @ResponseBody    public Object loginPost(String loginName, String password) throws IOException {        if (StringUtils.isBlank(loginName)) {            throw new RuntimeException("使用者名稱不可為空");        }        if (StringUtils.isBlank(password)) {            throw new RuntimeException("密碼不可為空");        }        Subject user = SecurityUtils.getSubject();        UsernamePasswordToken token = new UsernamePasswordToken(loginName, password);                try {            logger.info("開始登入");            user.login(token);            return renderSuccess("登陸成功");        } catch (UnknownAccountException e) {            throw new RuntimeException("帳號不存在!", e);        } catch (DisabledAccountException e) {            throw new RuntimeException("帳號未啟用!", e);        } catch (IncorrectCredentialsException e) {            throw new RuntimeException("密碼錯誤!", e);        } catch (Throwable e) {            throw new RuntimeException(e.getMessage(), e);        }    }

 

4、執行流程

使用者提交使用者名稱和密碼 --> shiro 封裝令牌 --> realm 通過使用者名稱將密碼查詢返回 --> shiro 自動去比較查詢出密碼和使用者輸入密碼是否一致--> 進行登陸控制。
login方法中調用user.login(token)後就會觸發protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)方法的執行。
代碼中使用SecurityUtils.getSubject().isPermitted("/public/getdatalist")時,會觸發protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
方法進行許可權認證。


java使用shiro小記

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.