前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >快速学习Shiro-Shiro的入门

快速学习Shiro-Shiro的入门

作者头像
cwl_java
发布2020-01-02 11:49:07
5300
发布2020-01-02 11:49:07
举报
文章被收录于专栏:cwl_Javacwl_Java

4. Shiro安全框架

4.4 Shiro的入门

4.4.1 搭建基于ini的运行环境

(1)创建工程导入shiro坐标

代码语言:javascript
复制
  <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

4.4.1 用户认证

认证:身份认证/登录,验证用户是不是拥有相应的身份。基于shiro的认证,是通过subject的login方法完成用户认证工作的 (1)在resource目录下创建shiro的ini配置文件构造模拟数据(shiro-auth.ini)

代码语言:javascript
复制
[users]
#模拟从数据库查询的用户
#数据格式   用户名=密码
zhangsan=123456
lisi=654321

(2)测试用户认证

代码语言:javascript
复制
 @Test
    public void testLogin() throws Exception{
        //1.加载ini配置文件创建SecurityManager
        Factory<SecurityManager> factory = new
IniSecurityManagerFactory("classpath:shiro.ini");
        //2.获取securityManager
        SecurityManager securityManager = factory.getInstance();
        //3.将securityManager绑定到当前运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //4.创建主体(此时的主体还为经过认证)
        Subject subject = SecurityUtils.getSubject();
        /**
         * 模拟登录,和传统等不同的是需要使用主体进行登录
         */
        //5.构造主体登录的凭证(即用户名/密码)
        //第一个参数:登录用户名,第二个参数:登录密码
        UsernamePasswordToken upToken = new UsernamePasswordToken("zhangsan","123456");
        //6.主体登录
        subject.login(upToken);
        //7.验证是否登录成功
        System.out.println("用户登录成功="+subject.isAuthenticated());
        //8.登录成功获取数据
        //getPrincipal 获取登录成功的安全数据
        System.out.println(subject.getPrincipal());
   }

4.4.2 用户授权

授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限

(1)在resource目录下创建shiro的ini配置文件构造模拟数据(shiro-prem.ini)

代码语言:javascript
复制
[users]
#模拟从数据库查询的用户
#数据格式   用户名=密码,角色1,角色2..
zhangsan=123456,role1,role2
lisi=654321,role2
[roles]
#模拟从数据库查询的角色和权限列表
#数据格式   角色名=权限1,权限2
role1=user:save,user:update
role2=user:update,user.delete
role3=user.find

(2)完成用户授权

代码语言:javascript
复制
public class ShiroTest1 {
    @Test
    public void testLogin() throws Exception{
        //1.加载ini配置文件创建SecurityManager
        Factory<SecurityManager> factory = new
IniSecurityManagerFactory("classpath:shiro.ini");
        //2.获取securityManager
        SecurityManager securityManager = factory.getInstance();
        //3.将securityManager绑定到当前运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //4.创建主体(此时的主体还为经过认证)
        Subject subject = SecurityUtils.getSubject();
        /**
         * 模拟登录,和传统等不同的是需要使用主体进行登录
         */
        //5.构造主体登录的凭证(即用户名/密码)
        //第一个参数:登录用户名,第二个参数:登录密码
        UsernamePasswordToken upToken = new UsernamePasswordToken("lisi","654321");
        //6.主体登录
        subject.login(upToken);
        //7.用户认证成功之后才可以完成授权工作
        boolean hasPerm = subject.isPermitted("user:save");
        System.out.println("用户是否具有save权限="+hasPerm);
         }
}

4.4.3 自定义Realm

Realm域:Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源

(1)自定义Realm

代码语言:javascript
复制
/**
* 自定义realm,需要继承AuthorizingRealm父类
*     重写父类中的两个方法
*         doGetAuthorizationInfo     :授权
*         doGetAuthenticationInfo     :认证
*/
public class PermissionRealm extends AuthorizingRealm {
    @Override
    public void setName(String name) {
        super.setName("permissionRealm");
   }
    /**
     * 授权:授权的主要目的就是查询数据库获取用户的所有角色和权限信息
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
principalCollection) {
        // 1.从principals获取已认证用户的信息
        String username = (String) principalCollection.getPrimaryPrincipal();
        /**
         * 正式系统:应该从数据库中根据用户名或者id查询
         *         这里为了方便演示,手动构造
         */
        // 2.模拟从数据库中查询的用户所有权限
        List<String> permissions = new ArrayList<String>();
        permissions.add("user:save");// 用户的创建
        permissions.add("user:update");// 商品添加权限
        // 3.模拟从数据库中查询的用户所有角色
        List<String> roles = new ArrayList<String>();
        roles.add("role1");
        roles.add("role2");
        // 4.构造权限数据
        SimpleAuthorizationInfo simpleAuthorizationInfo = new
SimpleAuthorizationInfo();
        // 5.将查询的权限数据保存到simpleAuthorizationInfo
        simpleAuthorizationInfo.addStringPermissions(permissions);
        // 6.将查询的角色数据保存到simpleAuthorizationInfo
        simpleAuthorizationInfo.addRoles(roles);
        return simpleAuthorizationInfo;
   }
    /**
     * 认证:认证的主要目的,比较用户输入的用户名密码是否和数据库中的一致
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken
authenticationToken) throws AuthenticationException {
        //1.获取登录的upToken
        UsernamePasswordToken upToken = (UsernamePasswordToken)authenticationToken;
        //2.获取输入的用户名密码
        String username = upToken.getUsername();
        String password = new String(upToken.getPassword());
        /**
         * 3.验证用户名密码是否正确
         * 正式系统:应该从数据库中查询用户并比较密码是否一致
         *         为了测试,只要输入的密码为123456则登录成功
         */
        if(!password.equals("123456")) {
            throw  new RuntimeException("用户名或密码错误");//抛出异常表示认证失败
       }else{
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, 
password,
                    this.getName());
            return info;
       }
   }
}

(2)配置shiro的ini配置文件(shiro-realm.ini)

代码语言:javascript
复制
[main]
#声明realm
permReam=cn.itcast.shiro.PermissionRealm
#注册realm到securityManager中
securityManager.realms=$permReam

(3)验证

代码语言:javascript
复制
public class ShiroTest2 {
    private SecurityManager securityManager;
    @Before
    public void init() throws Exception{
        //1.加载ini配置文件创建SecurityManager
        Factory<SecurityManager> factory = new
IniSecurityManagerFactory("classpath:shiro-realm.ini");
        //2.获取securityManager
        SecurityManager securityManager = factory.getInstance();
        //13.将securityManager绑定到当前运行环境
        SecurityUtils.setSecurityManager(securityManager);
   }
    @Test
    public void testLogin() throws Exception{
        //1.创建主体(此时的主体还为经过认证)
        Subject subject = SecurityUtils.getSubject();
        //2.构造主体登录的凭证(即用户名/密码)
        UsernamePasswordToken upToken = new UsernamePasswordToken("lisi","123456");
        //3.主体登录
        subject.login(upToken);
        //登录成功验证是否具有role1角色
        //System.out.println("当前用户具有role1="+subject.hasRole("role3"));
        //登录成功验证是否具有某些权限
        System.out.println("当前用户具有user:save权限="+subject.isPermitted("user:save"));
   }
}

4.4.4 认证与授权的执行流程分析

(1)认证流程

在这里插入图片描述
在这里插入图片描述
  1. 首先调用Subject.login(token)进行登录,其会自动委托给Security Manager,调用之前必须通过SecurityUtils. setSecurityManager()设置;
  2. SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
  3. Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现;
  4. Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;
  5. Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。

(2)授权流程

在这里插入图片描述
在这里插入图片描述
  1. 首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer
  2. Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;
  3. 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
  4. Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted/hasRole会返回true,否则返回false表示授权失败。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 4. Shiro安全框架
    • 4.4 Shiro的入门
      • 4.4.1 搭建基于ini的运行环境
      • 4.4.1 用户认证
      • 4.4.2 用户授权
      • 4.4.3 自定义Realm
      • 4.4.4 认证与授权的执行流程分析
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档