Shiro初级应用--小试牛刀体验shiro

最近在看Shiro安全框架,了解到了一些初级的应用,先记录一波shiro的认证和授权的简单应用,后续继续深入学习,再捋一捋shiro框架的架构和高级应用。

Apache Shiro是Java的一个安全框架。功能强大,使用简单的Java安全框架,它为开发人员提供一个直观而全面的认证,授权,加密及会话管理的解决方案。

Shrio是一款比较简单的安全框架,虽然Spring Security会简易很多,但是在我们一般的开发中已经足够保证安全了。

Shiro最简单的应用也是最重要的应用就是认证(Authentication)和授权(Authorization)。这两个单词很像,经常把他们看错了。认证就是验证用户登录信息是否正确,授权就是给予用户相应的权限。
这里还有一个概念,Realm,安全数据源,Shiro通过Realm获取用户的信息进行比较以确认身份,也可以通过Realm获取用户的权限。

下面写一个测试来验证认证和授权功能

项目结构
导入shiro依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.3.2</version>
</dependency>

1、测试登录认证
创建shiro-auth.ini配置文件

[users]
#模拟数据库中的用户
#数据格式  用户名=密码
admin=123456
hzm=111111

编写测试方法

public void testLogin() throws Exception{
    //加载ini配置文件并创建SecurityManager
    IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-auth.ini");
    //获取securityManager实例
    SecurityManager securityManager = factory.getInstance();
    //将securityManager绑定到当前运行环境
    SecurityUtils.setSecurityManager(securityManager);
    //创建主体(此时的主体还未经过认证)
    Subject subject = SecurityUtils.getSubject();
    /**
    * 模拟登录,和传统等不同的是需要使用主体进行登录
    */
    //构造主体登录的凭证(即用户名/密码,这里要跟配置文件里的用户密码比较)
    UsernamePasswordToken upToken = new UsernamePasswordToken("admin","123456");
    //登录
    subject.login(upToken);
    //验证是否登录成功
    System.out.println("用户登录成功="+subject.isAuthenticated());
    //登录成功获取数据
    //getPrincipal 获取登录成功的安全数据
    System.out.println(subject.getPrincipal());
}

测试结果
测试成功
如果我们的用户名密码不正确,会报错

org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - admin, 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 Test.testLogin(Test.java:24)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

2、测试授权
同样,我们通过配置的方法模拟数据库的权限,创建配置文件shiro-perm.ini

[users]
#模拟从数据库查询的用户
#数据格式  用户名=密码,角色1,角色2..
admin=123456,role1,role2
hzm=111111,role2
[roles]
#模拟从数据库查询的角色和权限列表
#数据格式  角色名=权限1,权限2
role1=user:save,user:update
role2=user:update,user.delete

测试方法

public void testPerm() throws Exception {
        //加载ini配置文件创建SecurityManager
        IniSecurityManagerFactory factory = new
                IniSecurityManagerFactory("classpath:shiro-perm.ini");
        //获取securityManager
        SecurityManager securityManager = factory.getInstance();
        //将securityManager绑定到当前运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //创建主体(此时的主体还为经过认证)
        Subject subject = SecurityUtils.getSubject();
        /**
         * 模拟登录,和传统不同的是需要使用主体进行登录
         */
        //构造主体登录的凭证(即用户名/密码,这里要跟配置文件里的用户密码比较)
        //第一个参数:用户名,第二个参数:密码
        UsernamePasswordToken upToken = new UsernamePasswordToken("hzm", "111111");
        //主体登录
        subject.login(upToken);
        //用户认证成功之后才可以完成授权工作
        boolean hasRole = subject.hasRole("role1");
        boolean hasPerm = subject.isPermitted("user:update");
        System.out.println("用户是否具有role1角色"+hasRole+",用户是否具有update权限=" + hasPerm);
    }

测试结果
在这里插入图片描述
对照配置文件,我们可以发现hzm用户不具有role1角色,但是具有user:update权限,测试结果正确。

3、通过自定义的Realm来认证和授权
shiro中自定义的Realm都要继承AuthorizingRealm,并且要重写doGetAuthorizationInfo(授权)和doGetAuthenticationInfo(认证)才能实现自定义的功能。
首先我们写一个PermissionRealm类

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

同样通过配置模拟Realm的使用过程
创建shiro-realm.ini文件

[main]
#声明realm
permReam=shiro.PermissionRealm
#注册realm到securityManager中
securityManager.realms=$permReam

测试方法

@Before
public void init() throws Exception{
    //加载ini配置文件创建SecurityManager
    IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
    //获取securityManager
    SecurityManager securityManager = factory.getInstance();
    //将securityManager绑定到当前运行环境
    SecurityUtils.setSecurityManager(securityManager);
}
@Test
public void testRealm() throws Exception{
    //创建主体(此时的主体还未经过认证)
    Subject subject = SecurityUtils.getSubject();
    //构造主体登录的凭证(即用户名/密码)
    UsernamePasswordToken upToken = new UsernamePasswordToken("hzm","88888");
    //主体登录,这里会调用realm的认证,认证通过后会调用授权方法
    subject.login(upToken);
    //登录成功验证是否具有role1角色
    System.out.println("当前用户具有role1="+subject.hasRole("role1"));
    //登录成功验证是否具有某些权限
    System.out.println("当前用户具有user:save权限="+subject.isPermitted("user:save"));
}

测试结果
在这里插入图片描述
本文只是对shiro的部分功能的小demo,后续会继续学习shiro更高级的东西并总结分享。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值