(3)shiro自定义realm
上面一章说到shiro的认证和授权最底层就是调用realm的getAuthorizationInfo(获取用户的角色和资源)和getAuthenticationInfo(校验账号密码是否正确)两个方法。
如果我们要从数据库中查询用户和他的权限信息,我们可以使用shiro提供给我们的JdbcRealm
JdbcRealm
添加jar
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.25</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>0.2.23</version> </dependency>
classpath环境下新建shiro-jdbc.ini如下配置
这里我们采用了阿里巴巴的数据源,注入到jdbcRealm的dataSource变量中,并且将这个jdbcRealm注入到securityManager,有点类似于spring的注入。
下面的sql放在github上对应的章节根目录下,导入即可,数据库密码填写自己数据库密码
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm dataSource=com.alibaba.druid.pool.DruidDataSource dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://localhost:3306/shiro dataSource.username=root dataSource.password=123456 jdbcRealm.dataSource=$dataSource #注入securityManager的realm securityManager.realms=$jdbcRealm
测试代码:
ShiroUtils.login("classpath:shiro-jdbc.ini","zhang","123456"); Subject subject = SecurityUtils.getSubject(); //是否通过认证 System.out.println(subject.isAuthenticated());
其中ShiroUtils的登录方法(这个以后直接略过):
public static void login(String configPath,String username,String password){ Factory<SecurityManager> factory =new IniSecurityManagerFactory(configPath); //得到安全管理器 SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { subject.login(token); } catch (AuthenticationException e) { e.printStackTrace(); } }
View Code
最后输出true。
因为jdbcRealm里面的sql都是固定的,所以我们表结构都要按照JdbcRealm里面创建对应的表。下面是JdbcRealm里面各种查询的sql(salt是密码加密,后面介绍加密再说,我们这里直接用明文密码)
表里面数据分别如下
接着测试代码添加如下:
System.out.println(subject.hasRole("role1"));
System.out.println(subject.isPermitted("user:create"));
最后输出true,false
为什么角色role1获取到了,permission没有获取到呢。
原因是JdbcRealm里面有个permissionsLookupEnabled默认是false,所以不会查询对应的资源权限,我们在配置文件中打开这个查询。
#打开permission查询 jdbcRealm.permissionsLookupEnabled=true
再查询就是true了。
自定义Realm
1 新增MyRealm类直接继承AuthorizingRealm.
public class MyRealm extends AuthorizingRealm { //认证信息, @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); String password = new String(upToken.getPassword()); //模拟用户名密码是否正确 if(!"zhang".equals(username)){ throw new UnknownAccountException(); } if(!"123456".equals(password)){ throw new IncorrectCredentialsException(); } return new SimpleAuthenticationInfo(username,password,getName()); } //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //获取用户名 String username = (String)getAvailablePrincipal(principals); //模拟从数据库查询出来对应的角色和权限 Set<String> roles = new HashSet<String>(); roles.add("role_1"); roles.add("role_2"); Set<String> permissions = new HashSet<String>(); permissions.add("user:create"); permissions.add("user:delete"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; } }
2,classpath文件下新建shiro-myrealm.ini配置文件
myrealm= com.nfcm.shiro.Realm.MyRealm
securityManager.realms=$myrealm
3,测试
ShiroUtils.login("classpath:shiro-myrealm.ini","zhang","123456"); Subject subject = SecurityUtils.getSubject(); //是否通过认证 System.out.println(subject.isAuthenticated()); //是否有role1角色 System.out.println(subject.hasRole("role_1")); System.out.println(subject.isPermitted("user:create"));
到这里全部测试通过。
github代码地址
https://github.com/cmniefei/shiroparent