shiro 学习

shiro 学习

@(shiro)[授权,认证,realm]

shiro 分为很多模块,主要学习授权、认证模块。另外的加密等模块也十分的好用,后期可以学习下。shiro官网地址:http://shiro.apache.org/


认证

大体就是实现登陆的功能模块,一般是由自定义的realm来实现用户身份验证逻辑。


shiro认证Demo

准备:shiro.ini、shiro实现类(log4j)

shiro.ini :充当数据库作用
shiro实现类:充当登录模块

shiro.ini

[users] ;指定下面的主体
lemontree=123456
jack=123

shiro实现类

/**
 * Created by lemontree on 2017/5/18.
 */
public class HelloWorld {
    public static void main(String[] args) {
        // 读取配置文件,初始化SecurityManager工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        // 获取SecurityManager实例
        SecurityManager securityManager = factory.getInstance();
        // 把SecurityManager实例绑定到SecurityUtils
        SecurityUtils.setSecurityManager(securityManager);
        // 获取当前用户
        Subject currentUser = SecurityUtils.getSubject();
        // 创建token令牌,用户名/密码
        UsernamePasswordToken token = new UsernamePasswordToken("lemontree","1234562");
        try {
            // 身份认证
            currentUser.login(token);
            System.out.println("身份认证成功");
        }catch (AuthenticationException e){
            e.printStackTrace();
            System.out.println("身份认证失败");
        }
        // 退出
        currentUser.logout();

    }
}

当身份验证失败则抛异常

org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - lemontree, rememberMe=false] did not match the expected credentials.
    at org.apache.shiro.realm.AuthenticatingRealm.assertCredentialsMatch(AuthenticatingRealm.java:600)
    at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:578)
    at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
    at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:267)
    at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)
    at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106)
    at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:270)
    at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:256)
    at com.lemontree.shiro.HelloWorld.main(HelloWorld.java:28)
Disconnected from the target VM, address: '127.0.0.1:60226', transport: 'socket'
身份认证失败

Demo认证过程:
Subject.login(token) 进行登录 -> securityManager.login -> (中间跳过部分流程)SimpleAccountRealm-> 从realm中取出信息(realm何时塞入?)对比 ,成功GG,出错抛异常。

realm何时塞入:其实在创建工厂(创建create securityManager)时就将信息塞入到iniRealm中去了。

看下源码:

    @SuppressWarnings({"unchecked"})
    private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {

        Map<String, ?> defaults = createDefaults(ini, mainSection);
        Map<String, ?> objects = buildInstances(mainSection, defaults);

        SecurityManager securityManager = getSecurityManagerBean();

        boolean autoApplyRealms = isAutoApplyRealms(securityManager);

        if (autoApplyRealms) {
            //realms and realm factory might have been created - pull them out first so we can
            //initialize the securityManager:
            Collection<Realm> realms = getRealms(objects);
            //set them on the SecurityManager
            if (!CollectionUtils.isEmpty(realms)) {
                applyRealmsToSecurityManager(realms, securityManager);
            }
        }

        return securityManager;
    }

认证重要的两个动作:
- 一个是读取配置文件,初始化SecurityManager工厂的时候
- 二是获取SecurityManager实例的时候
1. 初始化SecurityManager工厂的时,shiro主要是读取数据源(可能是.ini、url或其他文件File),并将信息存入名为sections的LinkedHashMap

shiro的组成与一些专业术语

来看看shiro官网有哪些东西
组成部分简介(以下内容复制张开涛老师的博客内容):
- Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
- Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
- Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
- Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
- Web Support:Web支持,可以非常容易的集成到Web环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
- Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
- Testing:提供测试支持;
- Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
- Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。
Alt text
@shiro从授权到认证在到加密、session管理一整套服务,很nice。

介绍下shiro的一些专业术语(以下复制张开涛老师的博客内容):
- principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。(从subject中获取
- credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。
- Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。如我们之前的ini配置方式将使用org.apache.shiro.realm.text.IniRealm。(其实第一个demo中的例子也是,将ini文件中的数据放入到iniRealm中进行读取
- Subject:主体,可以看到主体可以是任何可以与应用交互的“用户”;
- SecurityManager:相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。
- Authenticator:认证器,负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
Authrizer:授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

shiro整合spring

spring整合shiro无非需要三个点:
1. web.xml配置
2. spring配置(securityManager注入由spring来实现)
3. 实现自己的realm
官网有整合教程,链接如下:
shiro整合spring:http://shiro.apache.org/spring.html
shiro整合web:http://shiro.apache.org/web.html

与整合的Spring进行的认证主要逻辑是在自己实现的realm中进行的,自己的realm中实现doGetAuthenticationInfo方法(说实在的我老实搞混认证和授权的英文名),值得注意的是SimpleAuthenticationInfo中的password要与token的password要一致否则就是密码错误!,这是为什么那,在login一步一步下去中会发现,登录的过程就是在realm放回的SimpleAuthenticationInfo与token信息验证的过程!

/**
 * Created by lemontree on 2017/6/26.
 * 配置shiro域 realm的作用即是与数据库交互所用
 * 权限的实现就是在doGetAuthorizationInfo中将角色和对应权限塞入到对应的集合中
 * 让shiro来进行控制。
 */
public class SampleRealm extends AuthorizingRealm {

    public SampleRealm() {
        super();
    }

    /**
     * 认证
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        ShiroToken shiroToken = (ShiroToken) token;
        User user = userService.getUserByUserName(shiroToken.getUsername());
        if (null == user) {
            throw new AccountException("用户不存在!");
        }
        String psw = SHA256Util.getSHA256Str(shiroToken.getPswd());
        // 调用user的key对称加密进行对比
        if (!psw.equals(user.getPassword())) {
            throw new AccountException("用户密码错误!");
        }
        if (UserState.FROZEN_USER.getCode() == user.getUserState()) {
            throw new DisabledAccountException("改账号已被冻结!");
        } else {
            // 更新 登录信息
            user.setLastLoginTime(new Date());
            user.setLogincount(user.getLoginCount() + 1);
            userService.updateUser(user);
        }
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }
}

授权

实现用户的权限控制功能,用户->角色->权限


页面实现权限控制

授权的方式有三种:编程式、注解式、页面
在说页面授权之前先了解下权限是什么东西:开发过程中一般会有三种对象:用户、角色、权限,用户拥有一个或多个角色,每个角色有对应的权限(url权限)。
库表的设计大致如下:
enter image description here

页面的控制代码(JSP)大致是:

      <%--普通用户权限--%>
          <shiro:hasAnyRoles name="001">
              <shiro:hasPermission name="/index.htm">
                  <div><h1>index.htm有权限!</h1></div>
              </shiro:hasPermission>
              <shiro:hasPermission name="/register.htm">
                  <div><h1>register.htm有权限!</h1></div>
              </shiro:hasPermission>
          </shiro:hasAnyRoles>

那么,权限是什么时候获取的?
其实也是在realm中获取的,权限和角色都是通过下面的塞入到Set集合中,集合的泛型是String,在取的时候根据名称去控制权限。

public class SampleRealm extends AuthorizingRealm {

    public SampleRealm() {
        super();
    }

    /**
     * 授权
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Integer userId = TokenManager.getUserId();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 根据用户id获取用户角色,放入AuthorizationInfo
        Set<String> roles = roleService.getRolesByUserId(userId);
        info.setRoles(roles);
        // 根据用户id获取用户权限,放入AuthorizationInfo
        Set<String> permissions = permissionService.getPermissionByUserId(userId);
        info.setStringPermissions(permissions);
        return info;
    }

}

shiro的过滤器后期学习在补。

总结

shiro的认证和授权都是通过realm取数据然后对比

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值