Shiro(一)

Shiro(一)

最近项目里用到了shiro这个安全框架,之前没接触过安全框架,所以对一些基本概念的理解很是费劲,网上也搜了不少教程,最后实现起来也是磕磕绊绊,所以借此机会好好总结一下:什么是shirospringboot整合shiro如何实现,另外有时间的话,再针对核心源码进行解读。


shiro是什么

官方回答如下:

Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications.

Apache Shiro 是一个功能强大且易于使用的Java安全框架,它可以用于身份验证、授权、加密和会话管理。基于Shiro易于理解的API,您可以快速、轻松地保护任何应用程序——从小型的移动端程序到大型的web和企业应用程序。

几个核心概念
  • Subject

    Subject这个词是安全专业的专业术语,它指代当前正在运行(访问)的对象,这个对象可以是用户、第三方进程、守护进程账户或者类型的一些东西。Java程序员可以从Session角度理解。当一个用户成功登录的时候,传统的会话记录方式就是往session里存上<K, V>,这里的V可以理解成是Subject,这个V可以标识当前用户。

    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.SecurityUtils;
    ...
    Subject currentUser = SecurityUtils.getSubject();
    
  • SecurityManager

    SecurityManager对Subject进行统一配置、管理。是Shiro里最核心的一个组件。

  • Realms

    Realm中文意思就是“”。它是Shiro与应用程序间的“桥”或“连接器”。需要进行身份验证和授权时候,Shiro会从一个或多个域中查找所需内容。从某种意义上来说,它就是一个特定的DAO层,用以调用底层数据库。

    Shiro还提供了一些开箱即用的数据源,如LDAP、JDBC、INI等

    [main]
    ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
    ldapRealm.userDnTemplate = uid={0},ou=users,dc=mycompany,dc=com
    ldapRealm.contextFactory.url = ldap://ldapHost:389
    ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5 
    

    TIps在网上你或许也会看到很多shiro教程是这种格式的。因为Shiro的很多组件时可以通过配置文件来实现的,在某些应用领域是很方便的。当然对于注解爱好者的开发人员来说,它也是支持大量的注解,在springboot整合shiro章节再进行详述。

Authentication

身份验证。也就是平常写的登录接口的职能——验证用户名、密码。

在代码中就是要实现相应接口,然后实现身份验证的方法

当然也可以将身份验证的步骤进行细分,分成用户名验证、密码匹配验证等形式,这样做的目的可能是为了遵守”单一原则“的设计模式吧。

例如我的项目中,因为密码是加密存在数据库的,而这个加密规则也不是一两行代码搞定的,所以在身份验证方法中只是验证用户名的有效性,然后再另一个方法里去验证密码的正确性。

Subject Login

//1. Acquire submitted principals and credentials:
AuthenticationToken token = new UsernamePasswordToken(username, password);
//2. Get the current Subject:
Subject currentUser = SecurityUtils.getSubject();
//3. Login:
currentUser.login(token);

往常的登录接口就可以简单写成这样,然后具体的校验交给自己实现的方法来完成。

Authorization

授权。这个单词和身份验证的单词很像。一般的系统都是**用户-角色-菜单(url)**的权限模式,一个用户会属于一个角色类型(Administrator除外),一种角色能访问的菜单也是配置好的。当用户登录成功后,会根据用户角色去查询用户的权限菜单,然后前端予以展示。

这样简陋的权限模块,对于稍微能抓点包,看得懂HTTP报文的人来说,在他用领导账户帮忙处理一点任务的时候,只要记住了请求报文重要信息,便可以绕过前端页面的权限控制

所以呢,一般人会写个过滤器,每次请求都进行权限过滤。此法可行,但是不够灵活。比方说,我想针对每个接口进行针对性的过滤,或者某个接口只要拥有三个权限之一的权限就能访问,等等诸如此类的灵活管理就不太方便了。

高明一点的人,用自定义注解来实现。没错,shiro也提供了注解方式的权限配置。

    @RequiresPermissions(value = 
                             {"CLIENTINFO/FILE:SELECT","FILEINFO/SEARCH"}, 
                             logical = Logical.OR)
	@GetMapping("select")
	@ApiOperation("文件查看")
    public BaseResult select(@RequestParam String path,
                                   HttpServletResponse response) throws IOException {}

@RequiresPermissions(value = {"CLIENTINFO/FILE:SELECT","FILEINFO/SEARCH"},

logical = Logical.OR)指明,用户要访问这个接口时候,只要具备其中一种权限即可。

接着,程序会去调用Realm中自己实现的授权方法

 	@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = (User)principalCollection.getPrimaryPrincipal();
        if (user == null) {
            log.error("shiro getAuthorizationInfo failure");
            return new SimpleAuthorizationInfo();
        }
        List<Resources> resources;
        if (Constants.USER_ISSUPPER == user.getIssupper()) {
            resources = resourcesService.selectAllResources();
        } else {
            resources = resourcesService.selectResourcesByUser(user.getUsername());
        }
        Set<String> permissions = 		
            resources.stream().map(Resources::getId).collect(Collectors.toSet());
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }

authorizationInfo.setStringPermissions(permissions);将用户所拥有的权限Set赋值给授权信息对象。出于性能考虑,这里可以对资源集合获取增加Redis缓存。

Session Management

shiro的session管理是独立于容器的(Tomcat、Jetty等),方便跨端共享session。同时也可以自行实现session的缓存,这里缓存可以用Redis等NoSql数据库来进行存储。如果是集群、分布式环境需实现session的缓存管理相关方法。

Session session = subject.getSession();
session.getAttribute(“key”, someValue);
Date start = session.getStartTimestamp();
Date timestamp = session.getLastAccessTime();
session.setTimeout(millis);
Cryptography

加密。不用shiro的加密工具,就得自行使用JDK的MessageDigest类的静态方法来进行加密,相对来说比较麻烦

try {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.digest(bytes);
    byte[] hashed = md.digest();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} 

shiro以对象的形式来处理字符加密

String hex = new Md5Hash(myFile).toHex(); 
String encodedPassword =
    new Sha512Hash(password, salt, count).toBase64();

以上是shiro的一些常用的基本概念,如有误词,欢迎联系我指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值