什么是shiro?
Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。
为什么要用shiro?
既然可以基于url实现权限的管理,为什么还要用shiro呢??
1.shiro将安全认证相关的功能抽取出来组成一个框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。最主要的就是方便了我们的开发。
2.shiro使用广泛,shiro可以运行在web应用,非web应用,集群分布式应用中越来越多的用户开始使用shiro。
shiro认证
认证流程:
实例:
1.创建一个Java工程,并加入shiro-core的jar包以及它的依赖包。
2.自定义realm
Shiro有自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。
[java] view plain copy
1. public class CustomRealm extends AuthorizingRealm {
2.
3. @Override
4. public String getName() {
5. return "customRealm";
6. }
7.
8. // 用于认证
9. @Override
10. protected AuthenticationInfo doGetAuthenticationInfo(
11. throws AuthenticationException {
12.
13. // token是用户输入的
14. // 第一步从token中取出身份信息
15. String userCode = (String) token.getPrincipal();
16.
17. // 第二步:根据用户输入的userCode从数据库中查询
18. // 模拟从数据库查询到密码
19. "111111";
20.
21. // 如果查询到返回认证信息AuthenticationInfo
22.
23. new SimpleAuthenticationInfo(
24. this.getName());
25. return simpleAuthenticationInfo;
26. }
27. }
3.配置shiro-realm.ini文件
[html] view plain copy
1. [main]
2. #自定义realm
3. customRealm=cn.itcast.shiro.realm.CustomRealm
4. #将realm设置到securityManager,相当于spring中注入
5. securityManager.realms=$customRealm
4.创建认证代码
[java] view plain copy
1. // 用户登录和退出
2. @Test
3. public void testCustomRealm() {
4.
5. // 创建securityManager工厂,通过ini配置文件创建securityManager工厂
6. new IniSecurityManagerFactory(
7. "classpath:shiro-realm.ini");
8.
9. // 通过工厂创建SecurityManager
10. SecurityManager securityManager = factory.getInstance();
11.
12. // 将securityManager设置到运行环境中
13. SecurityUtils.setSecurityManager(securityManager);
14.
15. // 创建一个Subject实例,该实例认证要使用上边创建的securityManager进行
16. Subject subject = SecurityUtils.getSubject();
17.
18. // 创建token令牌,记录用户认证的身份和凭证即账号和密码
19. new UsernamePasswordToken("zhangsan",
20. "111111");
21.
22. try {
23. // 用户登陆
24. subject.login(token);
25. catch (AuthenticationException e) {
26. // TODO Auto-generated catch block
27. e.printStackTrace();
28. }
29.
30. // 用户认证状态
31.
32. Boolean isAuthenticated = subject.isAuthenticated();
33.
34. "用户认证状态:" + isAuthenticated);
35.
36. // 用户退出
37.
38. subject.logout();
39.
40. isAuthenticated = subject.isAuthenticated();
41.
42. "用户认证状态:" + isAuthenticated);
43.
44. }
5.认证流程
(1)创建token令牌,token中有用户提交的认证信息即账号和密码
(2)执行subject.login(token),最终由securityManager通过Authenticator进行认证
(3)Authenticator的实现ModularRealmAuthenticator调用realm从数据库中取用户真实的账号和密码
(4)CustomRealm先根据token中的账号去数据库中找该账号,如果找不到则给ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。
6.测试
登录时用户认证成功,退出时用户认证失败。
shiro授权
授权流程
授权方式
shiro支持三种方式的授权:
1.编程式
[java] view plain copy
1. Subject subject = SecurityUtils.getSubject();
2. if(subject.hasPermission(“admin”)) {
3. //有权限
4. } else {
5. //无权限
6. }
2.注解式
[java] view plain copy
1. @RequiresPermissions("admin")
2. public void hello() {
3. //有权限
4. }
3.JSP/GSP标签
[java] view plain copy
1. <shiro:hasPermission name="admin">
2. <!— 有权限—>
3. </shiro:hasRole>
在web系统集成中使用后两种方式,我在这儿举个简单的例子就用第一种方式了。
实例
1.自定义realm
[java] view plain copy
1. // 用于授权
2. @Override
3. protected AuthorizationInfo doGetAuthorizationInfo(
4. PrincipalCollection principals) {
5. // 获取身份信息
6. //将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到Simpl)
7. String username = (String) principals.getPrimaryPrincipal();
8.
9. // 根据身份信息从数据库中查询权限数据
10. // ....这里使用静态数据模拟
11. new ArrayList<String>();
12. "user:create");
13. "user:delete");
14.
15. // 将权限信息封闭为AuthorizationInfo
16. new SimpleAuthorizationInfo();
17. for (String permission : permissions) {
18. simpleAuthorizationInfo.addStringPermission(permission);
19. }
20.
21. return simpleAuthorizationInfo;
22.
23. }
2.配置shiro-realm.ini文件与上面认证配置文件相同
3.创建授权代码
[java] view plain copy
1. // 自定义realm进行资源授权测试
2. @Test
3. public void testAuthorizationCustomRealm() {
4.
5. // 从ini文件中创建SecurityManager工厂
6. new IniSecurityManagerFactory(
7. "classpath:shiro-realm.ini");
8.
9. // 创建SecurityManager
10. SecurityManager securityManager = factory.getInstance();
11.
12. // 将securityManager设置到运行环境
13. SecurityUtils.setSecurityManager(securityManager);
14.
15. // 创建主体对象
16. Subject subject = SecurityUtils.getSubject();
17.
18. // 对主体对象进行认证
19. // 用户登陆
20. // 设置用户认证的身份(principals)和凭证(credentials)
21. new UsernamePasswordToken("zhangsan",
22. "111111");
23. try {
24. subject.login(token);
25. catch (AuthenticationException e) {
26. // TODO Auto-generated catch block
27. e.printStackTrace();
28. }
29.
30. // 用户认证状态
31. Boolean isAuthenticated = subject.isAuthenticated();
32.
33. "用户认证状态:" + isAuthenticated);
34.
35. // 授权检测,失败则抛出异常
36. // subject.checkRole("role22");
37.
38. // 基于资源授权
39. "是否拥有某一个权限:" + subject.isPermitted("user:delete"));
40. "是否拥有多个权限:"
41. "user:update", "user:delete"));
42.
43. // 检查权限
44. "user:delete");
45.
46. }
4.授权流程
(1)执行subject.isPermitted("user:delete")
(2)securityManager通过ModularRealmAuthorizer进行授权
(3)ModularRealmAuthorizer调用realm获取权限信息
(4)ModularRealmAuthorizer再通过permissionResolver解析权限字符串,校验是否匹配
5.测试
表明该用户拥有delete权限但是不拥有update权限。