Shiro中的Realm

IniRealm可读取资源文件

resources下创建user.ini:

[users]
lyf=123qwe,admin
[roles]
admin=user:delete,user:update
public void testAuthentication(){

        //IniRealm可以读取resources下的指定文件
        IniRealm iniRealm = new IniRealm("classpath:user.ini");

        //认证第一步
        //1.构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //将Realm放入环境中
        defaultSecurityManager.setRealm(iniRealm);

        //2.由主体来提交认证请求
        //设置主体SecurityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //通过工具类获得主体
        Subject subject = SecurityUtils.getSubject();
        //获得主体之后,提交认证,即登录
        //这里用UsernamePasswordToken存认证数据
        UsernamePasswordToken token = new UsernamePasswordToken("lyf","123qwe");
        //进行登录认证
        subject.login(token);

        System.out.println("是否认证:" + subject.isAuthenticated());

        subject.checkRole("admin");

        //检测是否具备用户删除的权限
        subject.checkPermission("user:delete");
    }

运行结果:


JdbcRealm可以连接数据库
需要在pom.xml中导入依赖
     <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>

然后配置连接等,如下:

public class JdbcRealmTest {

    //创建数据源
    DruidDataSource dataSource = new DruidDataSource();
    //设置jdbc的url等
    {
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
    }

    @Test
    public void testAuthentication() {

        //JdbcRealm需要连接数据库,在pom总引入对应驱动包
        JdbcRealm jdbcRealm = new JdbcRealm();
        //设置jdbc数据源
        jdbcRealm.setDataSource(dataSource);

        //认证第一步
        //1.构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //将Realm放入SecurityManager环境中
        defaultSecurityManager.setRealm(jdbcRealm);

        //2.由主体来提交认证请求
        //设置主体SecurityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //通过工具类获得主体
        Subject subject = SecurityUtils.getSubject();
        //获得主体之后,提交认证,即登录
        //这里用UsernamePasswordToken存认证数据
        UsernamePasswordToken token = new UsernamePasswordToken("lyf", "123qwe");
        //进行登录认证
        subject.login(token);

        System.out.println("是否认证:" + subject.isAuthenticated());

    }
}

这里要注意的是JdbcRealm中有默认的一些sql语句:

根据sql去建一个users表:

运行认证测试,结果如下:

再看角色、授权,需要建立角色表user_roles:

还有授权表roles_permissions:

 这里验证用户角色使用subject.checkRole("admin");或者subject.checkRoles("admin","user");区别就在于后者可以传入多个角色进行验证,

但是这里要特别注意的是在设置jdbcRealm属性时,一定要把权限打开:

jdbcRealm.setPermissionsLookupEnabled(true);

否则就会以下报错:

org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [user:select]

    at org.apache.shiro.authz.ModularRealmAuthorizer.checkPermission(ModularRealmAuthorizer.java:323)
    at org.apache.shiro.mgt.AuthorizingSecurityManager.checkPermission(AuthorizingSecurityManager.java:137)
    at org.apache.shiro.subject.support.DelegatingSubject.checkPermission(DelegatingSubject.java:209)
    at lyf.top.test.JdbcRealmTest.testJdbcRealm(JdbcRealmTest.java:55)
    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)

贴上正确的代码:

public void testJdbcRealm() {

        //JdbcRealm需要连接数据库,在pom总引入对应驱动包
        JdbcRealm jdbcRealm = new JdbcRealm();
        //设置jdbc数据源
        jdbcRealm.setDataSource(dataSource);
        //设置权限开关,默认为false,若没有设置,
        // 在验证权限的时候,会报错Subject does not have permission
        jdbcRealm.setPermissionsLookupEnabled(true);

        //认证第一步
        //1.构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //将Realm放入SecurityManager环境中
        defaultSecurityManager.setRealm(jdbcRealm);

        //2.由主体来提交认证请求
        //设置主体SecurityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //通过工具类获得主体
        Subject subject = SecurityUtils.getSubject();
        //获得主体之后,提交认证,即登录
        //创建Token令牌,这里用UsernamePasswordToken存认证数据
        UsernamePasswordToken token = new UsernamePasswordToken("lyf", "123qwe");
        //进行登录认证
        subject.login(token);

        System.out.println("是否认证:" + subject.isAuthenticated());

        //检验当前账号角色
        subject.checkRole("admin");
        //检验当前账号是否同时具备两个角色admin、user
        subject.checkRoles("admin","user");

        subject.checkPermission("user:select");

    }

而在实际开发中,不可能用到它自带的sql,因为我们自己的表字段不可能跟它一样,所以需要使用自定义sql:

        //自定义登录验证的sql语句
        String sql = "select password from test_user where user_name = ?";
        jdbcRealm.setAuthenticationQuery(sql);

        //自定义验证角色的sql语句
        String rolSql = "select role_name from test_user_role where user_name = ?";
        jdbcRealm.setUserRolesQuery(rolSql);

其他操作照常不变。


自定义Realm

首先创建自定义Realm,CustomRealm.java:

public class CustomRealm extends AuthorizingRealm {

    Map<String,String > userMap = new HashMap<>(16);

    {
        userMap.put("lyf","123qwe");
        super.setName("customRealm");
    }

    //授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        return null;
    }

    //认证
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        //1.通过主体传过来的认证信息中去获取用户名
        String userName = (String)authenticationToken.getPrincipal();

        //2.通过用户名到数据库中获取凭证
        String password = getPasswordByUserName(userName);
        if (password == null){
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo
                ("lyf",password,"customRealm");

        return authenticationInfo;
    }

    /**
     * 模拟数据库查询凭证
     * @param userName
     * @return
     */
    private String getPasswordByUserName(String userName){

        return userMap.get(userName);
    }
}

这里只写了认证,接着测试这个自定义的Realm:

public class CustomRealmTest {
    @Test
    public void testAuthentication() {

        //创建自定义Realm对象
        CustomRealm customRealm = new CustomRealm();


        //认证第一步
        //1.构建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);

        //2.由主体来提交认证请求
        //设置主体SecurityManager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //通过工具类获得主体
        Subject subject = SecurityUtils.getSubject();
        //获得主体之后,提交认证,即登录
        //这里用UsernamePasswordToken存认证数据
        UsernamePasswordToken token = new UsernamePasswordToken("lyf", "123qwe");
        //进行登录认证
        subject.login(token);

        System.out.println("是否认证:" + subject.isAuthenticated());

        /*subject.checkRole("admin");

        //检测是否具备用户删除的权限
        subject.checkPermission("user:delete");*/
    }
}

运行结果如下:

接着是写自定义Realm中的授权操作:

    //授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        String userName = (String) principalCollection.getPrimaryPrincipal();
        //实际开发时这里是从数据库或者缓存中获取角色数据
        Set<String> roles = getRolesByUserName(userName);

        Set<String> permissions = getPermissionsByUserName();
        //将取来的角色数据与权限数据返回
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //设置权限
        simpleAuthorizationInfo.setStringPermissions(permissions);
        //设置角色
        simpleAuthorizationInfo.setRoles(roles);

        return simpleAuthorizationInfo;
    }

    private Set<String> getPermissionsByUserName() {
        Set<String> sets= new HashSet<>();
        sets.add("user:delete");
        sets.add("user:add");
        return sets;
    }

    private Set<String> getRolesByUserName(String userName) {
        Set<String> sets = new HashSet<>();
        sets.add("admin");
        sets.add("user");
        return sets;
    }

添加测试:

       subject.checkRole("admin");
       subject.checkPermissions("user:add","user:delete");

运行结果如下:

原文地址:https://www.cnblogs.com/xk920/p/10814771.html