Apache Shiro 认证+授权

Posted kibana

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Apache Shiro 认证+授权相关的知识,希望对你有一定的参考价值。

1、核心依赖

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

2、认证流程:创建SecurityManager-->主体提交认证-->SecurityMananger认证-->Authentictor认证-->Realm验证(从subject.login(token)开始跟踪源码可以验证(idea下ctrl+alt+b跟踪源码)),单元测试代码如下:

package com.example.demo_mg;

import junit.framework.Assert;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoMgApplicationTests 

    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    @Before
    public void before() 
        simpleAccountRealm.addAccount("wzs", "123456");
    

    @Test
    public void contextLoads() 
    

    @Test
    public void test() 
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);
        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("wzs", "123456");
        subject.login(token);
        Assert.assertEquals(subject.isAuthenticated(), true);
        subject.logout();
        Assert.assertEquals(subject.isAuthenticated(), true);
    

账号错误UnknownAccountException,密码错误IncorrectCredentialsException。

从subject.login(token);点击ctrl+alt+b跟踪源码到DelegatingSubject的login方法,调用Subject subject = this.securityManager.login(this, token);,继续跟踪到DefaultSecurityManager的login方法,调用info = this.authenticate(token);,继续跟踪到AuthenticatingSecurityManager的authenticate方法,调用this.authenticator.authenticate(token);,继续跟踪到AbstractAuthenticator的authenticate方法,调用info = this.doAuthenticate(token);,继续跟踪到ModularRealmAuthenticator的doAuthenticate方法,可以看到如下认证代码,通过realm实现认证:

    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException 
        this.assertRealmsConfigured();
        Collection<Realm> realms = this.getRealms();
        return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
    

3、授权流程:创建SecurityManager-->主体授权-->SecurityManager授权-->Authorizer授权-->Realm获取角色权限数据(数据库|缓存等):

package com.example.demo_mg;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoMgApplicationTests 

    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    @Before
    public void before() 
        simpleAccountRealm.addAccount("wzs", "123456", "admin", "user");
    

    @Test
    public void contextLoads() 
    

    @Test
    public void test() 
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);
        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("wzs", "123456");
        subject.login(token);
        //授权
        subject.checkRole("admin");
        subject.checkRoles("admin", "user");
        subject.logout();
    

角色不存在UnauthorizedException

从subject.checkRoles("admin", "user");点击ctrl+alt+b跟踪源码到DelegatingSubject的checkRoles方法,调用this.securityManager.checkRoles(this.getPrincipals(), roleIdentifiers);,继续跟踪到AuthorizingSecurityManager的checkRoles方法,调用this.authorizer.checkRoles(principals, roles);,继续跟踪到ModularRealmAuthorizer的checkRoles方法,遍历roles调用this.checkRole(principals, role);,继续跟踪到checkRole方法,调用this.hasRole(principals, role),继续跟踪到hasRole方法,可见如下代码,通过realm授权:

    public boolean hasRole(PrincipalCollection principals, String roleIdentifier) 
        this.assertRealmsConfigured();
        Iterator var3 = this.getRealms().iterator();

        Realm realm;
        do 
            if (!var3.hasNext()) 
                return false;
            

            realm = (Realm)var3.next();
         while(!(realm instanceof Authorizer) || !((Authorizer)realm).hasRole(principals, roleIdentifier));

        return true;
    

4、测试内置的IniRealm:
在src/test下新建Direcotry,名称resources,右键Mark Direcotry As-->Test Sources Root,在下面新建user.ini文件,内容:

[users]
wzs=123456,admin
[roles]
admin=user:delete,user:update

单元测试代码:

package com.example.demo_mg;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoMgApplicationTests 

    @Test
    public void contextLoads() 
    

    @Test
    public void test() 
        IniRealm iniRealm = new IniRealm("classpath:user.ini");
        //构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);
        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("wzs", "123456");
        subject.login(token);
        //授权
        subject.checkRole("admin");
        subject.checkPermissions("user:delete", "user:update");
        subject.checkPermission("user:insert");
        subject.logout();
    

权限不存在UnauthorizedException

以上是关于Apache Shiro 认证+授权的主要内容,如果未能解决你的问题,请参考以下文章

Apache Shiro 认证授权加密和会话管理

在 Web 项目中应用 Apache Shiro

03-Apache Shiro 安全框架(练一个)

Apache Shiro 使用手册Shiro架构介绍

Apache Shiro 使用手册Shiro架构介绍

Apache Shiro Stateless - 无会话 JWT 令牌认证问题