1. 程式人生 > >Shiro的簡單使用

Shiro的簡單使用

一、shiro認證

1、請求認證
Subject subject = SecurityUtils.getSubject();// 根據執行環境返回subject
subject.login(token);// 這裡的token一般指的是 UsernamePasswordToken,引數有
                     // String username, String password, boolean rememberMe, String host ,有多種建構函式
2、通過SecurityManager執行認證
public void login(AuthenticationToken token) throws
AuthenticationException { this.clearRunAsIdentitiesInternal(); Subject subject = this.securityManager.login(this, token);// 呼叫securityManager String host = null; PrincipalCollection principals; if (subject instanceof DelegatingSubject) { DelegatingSubject delegating = (DelegatingSubject)subject; principals = delegating.principals; host = delegating.host; } else
{ principals = subject.getPrincipals(); }// 無論怎麼樣principals = subject.getPrincipals();既使用者名稱 if (principals != null && !principals.isEmpty()) { this.principals = principals; this.authenticated = true; if (token instanceof HostAuthenticationToken) { host = ((HostAuthenticationToken)token).getHost(); } if
(host != null) { this.host = host; } Session session = subject.getSession(false); if (session != null) { this.session = this.decorate(session); } else { this.session = null; } } else { String msg = "Principals returned from securityManager.login( token ) returned a null or empty value. This value must be non null and populated with one or more elements."; throw new IllegalStateException(msg); } }
3、SecurityManager通過ModularRealmAuthenticator再通過realm進行認證

在自定義的Realm中完成認證

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    //獲取使用者的輸入的賬號.
    String username = (String) token.getPrincipal();
    User user = userService.selectByUsername(username);
    String password = user.getPassword();
    if (user == null) throw new UnknownAccountException();
    if (0 == user.getEnable()) {
        throw new LockedAccountException(); // 帳號鎖定
    }

    //通過這個進行認證,並返回
    SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, null, getName());

    Session session = SecurityUtils.getSubject().getSession();// 當驗證都通過後,把使用者資訊放在session裡
    session.setAttribute("userSession", user);
    session.setAttribute("userSessionId", user.getId());
    return simpleAuthenticationInfo;
}
4、認證的配置

這些配置在shiro的配置檔案中完成

    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());// 憑證驗證器
        return myShiroRealm;
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {// 憑證驗證器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("md5");//雜湊演算法:這裡使用MD5演算法;
        hashedCredentialsMatcher.setHashIterations(1);//雜湊的次數,比如雜湊兩次,相當於 md5(md5(""));

        return hashedCredentialsMatcher;
    }

二、shiro授權

1、ModularRealmAuthenticator通過realm進行認證

在自定義的Realm中完成授權,將使用者的許可權查出,配置到info中去。

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

    String username = (String) principalCollection.getPrimaryPrincipal();
    User user = userService.selectByUsername(username);

    Map<String, Object> map = new HashMap();
    map.put("userid", user.getId());

    List<Resources> resourcesList = resourcesService.loadUserResources(map);

    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();  // 許可權資訊物件info
    for (Resources resources : resourcesList) {
        info.addStringPermission(resources.getResurl()); // 在這裡存放查出的使用者的所有的角色(role)及許可權(permission)
    }
    return info;
}
2、授權的配置,通過filterChainDefinitionMap在Shiro的攔截器中配置

這些配置在shiro的配置檔案中完成

   @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setSuccessUrl("/usersPage");// 登入成功跳轉的頁
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");// 未授權介面;

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
        filterChainDefinitionMap.put("/logout", "logout");// 配置登出地址,不需要專門去寫控制器
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/font-awesome/**", "anon");// 首先放過一般的靜態資源

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); // 配置所有需要攔截的地址
        return shiroFilterFactoryBean;
    }
2.1配置規則
// 將需要配置的地址放入map中,規則如下:
/**
anon:例子/admins/**=anon 沒有引數,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要認證(登入)才能使用,沒有引數

roles(角色):例子/admins/user/**=roles[admin],引數可以寫多個,多個時必須加上引號,
並且引數之間用逗號分割,當有多個引數時,例如admins/user/**=roles["admin,guest"],
每個引數通過才算通過,相當於hasAllRoles()方法。

perms(許可權):例子/admins/user/**=perms[user:add:*],引數可以寫多個,多個時必須加上引號,
並且引數之間用逗號分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],
當有多個引數時必須每個引數都通過才通過,想當於isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根據請求的方法,相當於/admins/user/**=perms[user:method] ,
其中method為post,get,delete等。

port:例子/admins/user/**=port[8081],當請求的url的埠不是8081是跳轉到
schemal://serverName:8081?queryString,其中schmal是協議http或https等,
serverName是你訪問的host,8081是url配置裡port的埠,queryString是你訪問的url裡的?後面的引數。

authcBasic:例如/admins/user/**=authcBasic沒有引數表示httpBasic認證

ssl:例子/admins/user/**=ssl沒有引數,表示安全的url請求,協議為https

user:例如/admins/user/**=user沒有引數表示必須存在使用者,當登入操作時不做檢查
*/
// 詳情參考shiro.web.filter原始碼

三、shiro結合thymeleaf實現細粒度許可權控制

在shiro的配置檔案中加入

@Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

html中加入xmlns

<html lang="zh_CN" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

maven依賴

<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>1.2.1</version> 
</dependency>