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");
运行结果如下: