Shiro安全管理框架(二)

1,287 阅读5分钟

一、创建项目

执行tree ./src/main/java/命令,查看项目。

./src/main/java/
└── javaboy
    └── greamrod
        ├── DemoApplication.java
        ├── MainApp.java
        ├── entity
        │   └── User.java
        └── shiro
            ├── ShiroRealm.java
            └── ShiroUtils.java

创建SpringBoot项目,导入shiro-spring的依赖包。

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.5.3</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

二、创建User实体类

javaboy.greamrod.entity根包下,并创建User实体类。

package javaboy.greamrod.entity;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String username;
    private String password;
    private Integer status;     //0:正常、1:禁用、2:锁定
}

三、创建自定义的Realm

javaboy.greamrod.shiro根包下,并创建ShiroRealm类。

提示:

doGetAuthenticationInfo()方法中,可以修改User user = new User("zhangsan", "123", 2);代码,测试认证方法的异常

doGetAuthorizationInfo方法中,可以修改info.addRoles();、info.addStringPermissions()代码,来判断当前用户对某个资源是否有角色权限

package javaboy.greamrod.shiro;

/**
 * 自定义的Realm
 */
public class ShiroRealm extends AuthorizingRealm {
    /**
     * 执行授权逻辑
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.err.println("-- 执行授权逻辑 --");
        Object principal = principals.getPrimaryPrincipal();
        System.err.println("principals >>> "+ principals);
        System.err.println("principal >>> "+ principal);

        //TODO 模拟根据`username`查询数据库中查询,指定`user` --> 角色、权限。
        Collection<String> roles = new HashSet<>();
        roles.add("admin");
        roles.add("guest");
        Collection<String> permissions = new HashSet<>();
        permissions.add("product:view");    //查看产品列表
        permissions.add("product:create");  //创建产品
        permissions.add("product:edit");    //编辑产品
        permissions.add("product:remove");  //删除产品

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }

    /**
     * 执行认证逻辑
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.err.println("-- 执行认证逻辑 --");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String password = new String(token.getPassword());
        System.err.println("username >>> "+ username);
        System.err.println("password >>> "+ password);

        //TODO 模拟根据`username`查询数据库中查询指定`user`记录。
        User user = new User("zhangsan", "123", 0);
        if (user == null) {
            throw new UnknownAccountException("账户不存在异常!!!");
        }else if (! user.getPassword().equals(password)) {
            throw new CredentialsException("密码不存在异常!!!");
        }else if (user.getStatus() == 1) {
            throw new DisabledAccountException("用户被禁用异常!!!");
        }else if(user.getStatus() == 2) {
            throw new LockedAccountException("用户被锁定异常!!!");
        }

        String realName = getName();
        Object principal = token.getPrincipal();
        Object credentials = token.getCredentials();
        System.err.println("realName >>> "+ realName);
        System.err.println("principal >>> "+ principal);    //username
        System.err.println("credentials >>> "+ credentials.toString());    //password
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realName);
        return info;
    }
}

四、搭建Shiro安全管理框架

javaboy.greamrod.shiro根包下,创建ShiroUtils类。该类提供了搭建shiro框架方法登录方法登出方法

package javaboy.greamrod.shiro;

public class ShiroUtils {
    /**
     * 搭建Shiro的框架
     */
    public static void buildShiro()  {
        //创建自定义Realm对象
        ShiroRealm realm = new ShiroRealm();
        //创建SecurityManager安全管理器,并注入自定义的Realm
        SecurityManager securityManager = new DefaultSecurityManager(realm);
        //使用SecurityUtils将SecurityManager设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
    }

    /**
     * 执行登录操作
     * @param username  登录账号
     * @param password  账号密码
     */
    public static void login(String username, String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
    }

    /**
     * 执行登出操作
     */
    public static void logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
    }
}

五、测试shiro安全管理框架

javaboy.greamrod根包下,创建MainApp类,并测试shiro框架。

package javaboy.greamrod;

public class MainApp {
    public static void main(String[] args) {
        /**
         * 1、搭建Shiro框架
         */
        ShiroUtils.buildShiro();

        /**
         * 2、执行登录操作
         */
        Subject subject = SecurityUtils.getSubject();
        System.err.println("Before Login 用户登录状体 >>> "+ subject.isAuthenticated());
        String username = "zhangsan";
        String password = "123";
        ShiroUtils.login(username, password);
        System.err.println("After Login 用户登录状体 >>> "+ subject.isAuthenticated());

        System.err.println("是否拥有[admin]角色 >> "+ subject.hasRole("admin"));
        boolean[] rolesBoolList = subject.hasRoles(Arrays.asList("admin", "guest"));
        System.err.println("是否拥有[admin、guest]角色 >> "+ Arrays.toString(rolesBoolList));
        System.err.println("是否拥有[product:view]权限 >> "+ subject.isPermitted("product:view"));
        boolean[] permittedBoolList = subject.isPermitted("product:view", "product:edit", "product:create", "product:remove");
        System.err.println("是否拥有[product的view、edit、create、remove]的权限 >> "+ Arrays.toString(permittedBoolList));

        /**
         * 3、执行登出操作
         */
        ShiroUtils.logout();
    }
}

输出如下:

Before Login 用户登录状体 >>> false

-- 执行认证逻辑 --
username >>> zhangsan
password >>> 123
realName >>> javaboy.greamrod.shiro.ShiroRealm_0
principal >>> zhangsan
credentials >>> [C@6073f712

After Login 用户登录状体 >>> true

-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
是否拥有[admin]角色 >> true

-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
是否拥有[admin、guest]角色 >> [true, true]

-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
是否拥有[product:view]权限 >> true

-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
-- 执行授权逻辑 --
principals >>> zhangsan
principal >>> zhangsan
是否拥有[product的view、edit、create、remove]的权限 >> [true, true, true, true]

shiro框架中什么时候调用自定义Realm类中的认证方法、权限方法

  1. 什么时候调用认证方法:
  • SecurityUtils.getSubject().login()方法,就会调用自定义Realm类中的doGetAuthenticationInfo()认证方法。
  1. 什么时候调用授权方法:

    是否拥有角色:

  • 执行SecurityUtils.getSubject().hasRole("admin")方法,就会执行一次自定义Realm类中的doGetAuthorizationInfo()授权方法。

  • 执行SecurityUtils.getSubject().hasRoles(Arrays.asList("admin", "guest")方法,就会执行两次自定义Reaml类中的doGetAuthorizationInfo()方法。

    是否拥有权限:

  • 执行SecurityUtils.getSubject().isPermitted("product:view")方法,就会执行一次自定义Realm类中的doGetAuthorizationInfo()授权方法。

  • 执行SecurityUtils.getSubject().isPermitted("product:view", "product:edit", "product:create", "product:remove")方法,就会执行四次自定义Reaml类中的doGetAuthorizationInfo()方法。

Shrio框架中的提供异常信息

ShiroException
    |---UnknownAccountException
    |---CredentialsException
    |---DisabledAccountException
    |---LockedAccountException
  • UnknownAccountException异常
//抛出UnknownAccountException异常:
if (user == null) {
    throw new UnknownAccountException("账户不存在异常!!!");
}
=========================================================================================
//异常信息:
Exception in thread "main" org.apache.shiro.authc.UnknownAccountException: 账户不存在异常!!!
	at javaboy.greamrod.shiro.ShiroRealm.doGetAuthenticationInfo(ShiroRealm.java:63)
	at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:273)
	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:275)
	at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260)
	at javaboy.greamrod.shiro.ShiroUtils.login(ShiroUtils.java:30)
	at javaboy.greamrod.MainApp.main(MainApp.java:23)
  • CredentialsException异常
//抛出CredentialsException异常:
if (! user.getPassword().equals(password)) {
    throw new CredentialsException("密码不存在异常!!!");
}
=========================================================================================
//异常信息:
Exception in thread "main" org.apache.shiro.authc.CredentialsException: 密码不存在异常!!!
	at javaboy.greamrod.shiro.ShiroRealm.doGetAuthenticationInfo(ShiroRealm.java:65)
	at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:273)
	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:275)
	at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260)
	at javaboy.greamrod.shiro.ShiroUtils.login(ShiroUtils.java:30)
	at javaboy.greamrod.MainApp.main(MainApp.java:23)
  • DisabledAccountException异常
//抛出DisabledAccountException异常:
if (user.getStatus() == 1) {
    throw new DisabledAccountException("用户被禁用异常!!!");
}
=========================================================================================
//异常信息:
Exception in thread "main" org.apache.shiro.authc.DisabledAccountException: 用户被禁用异常!!!
	at javaboy.greamrod.shiro.ShiroRealm.doGetAuthenticationInfo(ShiroRealm.java:67)
	at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:273)
	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:275)
	at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260)
	at javaboy.greamrod.shiro.ShiroUtils.login(ShiroUtils.java:30)
	at javaboy.greamrod.MainApp.main(MainApp.java:23)
  • LockedAccountException异常
//抛出LockedAccountException异常:
if(user.getStatus() == 2) {
    throw new LockedAccountException("用户被锁定异常!!!");
}
=========================================================================================
//异常信息:
Exception in thread "main" org.apache.shiro.authc.LockedAccountException: 用户被锁定异常!!!
	at javaboy.greamrod.shiro.ShiroRealm.doGetAuthenticationInfo(ShiroRealm.java:69)
	at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
	at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:273)
	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:275)
	at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260)
	at javaboy.greamrod.shiro.ShiroUtils.login(ShiroUtils.java:30)
	at javaboy.greamrod.MainApp.main(MainApp.java:23)