banner
NEWS LETTER

shiro

Scroll down

shiro介绍

​ Apache Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了

环境搭建

1 导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- spring boot整合shiro所需要的依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>

<!--shiro标签所需依赖-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency

2 创建realm类,继承接口AuthorizingRealm

1
public class MyRealm extends AuthorizingRealm 

3 创建shiro配置类ShiroConfig ,并自行加上未经授权页面noPower.html和login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
@Configuration
public class ShiroConfig {
/**
* 配置密码匹配器
* @return
*/
@Bean(name={"hashedCred"})
public HashedCredentialsMatcher getMatcher(){
HashedCredentialsMatcher hsc = new HashedCredentialsMatcher();
//加密算法
hsc.setHashAlgorithmName("MD5");
//加密次数
hsc.setHashIterations(1024);
return hsc;
}
/**
* 配置自定义的 realm
* @param hs
* @return
*/
@Bean(name={"myRealm"})
public MyRealm getRealm(@Qualifier("hashedCred") HashedCredentialsMatcher hs ){
MyRealm realm = new MyRealm();
realm.setCredentialsMatcher(hs);
return realm;
}
/**
* 配置安全管理类
* @return
*/
@Bean(name={"securityManager"})
public DefaultWebSecurityManager getSecurity(@Qualifier("myRealm") MyRealm realm){
DefaultWebSecurityManager dm = new DefaultWebSecurityManager();
dm.setRealm(realm);
return dm;
}

@Bean
public LifecycleBeanPostProcessor getProcess(){
return new LifecycleBeanPostProcessor();
}

//html 标签配置
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
/**
* 配置权限
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilter(@Qualifier("securityManager") DefaultWebSecurityManager sm){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(sm);
//配置登录页面
bean.setLoginUrl("/login");
//配置无此权限访问页面
bean.setUnauthorizedUrl("/noPower");

return bean;
}
}

4 创建一个MD5的工具类,用来新增用户密码和修改用户密码 进行密码加密处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @Author 伍军
*/
@Component
public class MdFive {
/**
*
* @param password 要加密的密码
* @param saltValue 盐值
* @return
*/
public String encrypt(String password,String saltValue){
//创建一个MD5的盐值对象
Object salt = new Md5Hash(saltValue);
//生成加密的字符串
Object result = new SimpleHash("MD5", password, salt, 1024);

return result+"";
}

}

shiro认证

认证即是 身份验证,即在应用中谁能证明他就是他本人。一般提供如他们的身份 ID 一些标识信息来表明他就是他本人,如提供身份证,用户名 / 密码来证明。

在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,从而应用能验证用户身份:

principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个 principals,但只有一个 Primary principals,一般是用户名 / 密码 / 手机号。

credentials:证明 / 凭证,即只有主体知道的安全值,如密码 / 数字证书等。

最常见的 principals 和 credentials 组合就是用户名 / 密码了。接下来先进行一个基本的身份认证。

实现用户密码MD5加密登录实现: 实现步骤如下:

1 Service层接口重新定义一个登录接口方法。

1
HashMap<String,Object> loginShiro(UserInfo userInfo, HttpServletRequest request );

2 Service层接口实现类代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public HashMap<String, Object> loginShiro(UserInfo userInfo, HttpServletRequest request) {
HashMap<String, Object> map = new HashMap<String, Object>();
//创建一个令牌
UsernamePasswordToken token = new UsernamePasswordToken(userInfo.getUserName(),userInfo.getUserPwd());
try {
//登录
sub.login(token);
//存入登录用户信息
HttpSession session = request.getSession();
session.setAttribute("user",user);
map.put("info",true);
} catch(IncorrectCredentialsException ie){
//密码异常
System.err.println("密码不正确");
map.put("info","密码不正确");
}catch (UnknownAccountException e){
e.printStackTrace();
map.put("info","用户名输入错误");
}


return map;
}

3 实现myreal类的认证方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserInfoService userInfoService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
*认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户凭证
UsernamePasswordToken myToken = (UsernamePasswordToken)token;
//获取登录的用户名
String userName = myToken.getPrincipal()+"";

UserInfo userInfo =userInfoService.findByUserName(userName);
//判断用户名是否正确
if(userInfo==null){
throw new UnknownAccountException();
}
//密码和其他的验证
AuthenticationInfo auth = new SimpleAuthenticationInfo(
userInfo.getUserName(), userInfo.getUserPwd(),new Md5Hash(userName),this.getName());

return auth;
}
}

4 服务端代码完毕,前端页面简单这里就不贴了

5 与身份验证相关的过滤器

authc 表示访问该链接,必须要进行登录认证

例如 :/index.do=authc

anon 匿名过滤器,即不需要登录即可访问

例如:/login.jsp=anon

logout 退出过滤器,

注意:控制器无需定义logout.do地址,页面有这个地址就可以了

例如:/logout.do=logout

shiro授权

授权

授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。

主体

主体,即访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权后才允许访问相应的资源。

资源

在应用中用户可以访问的任何东西,比如访问 JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。

权限

权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允许,不反映谁去执行这个操作。所以后续还需要把权限赋予给用户,即定义哪个用户允许在某个资源上做什么操作(权限),Shiro 不会去做这件事情,而是由实现人员提供。

例如:查看/新增/修改/删除用户数据(即很多时候都是 CRUD(增查改删)式权限控制)

角色

角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。

授权实现思路

在自定义的myreaml中doGetAuthorizationInfo 方法中实现

1 获取身份验证通过的用户名

1
Object userName =principals.fromRealm(this.getName()).iterator().next();

2 根据用户名查询去数据库查询用户拥有的权限或者角色

1
2
//查询拥有拥有的角色信息
UserInfo u= userInfoMapper.queryByName(userName);

3 创建shiro授权对象

1
SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();

4 给用户赋予权限或者角色

1
2
3
4
5
    //给用户赋予角色

simpleAuthorInfo.addRoles(查询出来的当前用户角色集合);
//给用户赋予权限
simpleAuthorInfo.addStringPermissions(查询出来的当前用户权限集合);

5 返回授权对象

1
return simpleAuthorInfo;

6 完整授权代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取登录的用户
String userName =principals.fromRealm(this.getName()).iterator().next()+"";
//查询拥有拥有的角色信息
UserInfo u= userInfoMapper.queryByName(userName);
List<String> list = new ArrayList<>();
for(RoleInfo r:u.getRoleInfoList()){
list.add(r.getRemark());
System.err.println("给用户"+userName+"赋予了"+r.getRemark()+"角色");
}
SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
//创建权限凭证,添加角色的方法addRoles
//添加权限的方法 addStringPermissions
auth.addRoles(list);

return auth;
}

7 授权功能要实现需要配置 过滤器 或者 权限标签才能实现,配置过滤器代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
      @Bean
public ShiroFilterFactoryBean getShiroFilter(@Qualifier("securityManager") DefaultWebSecurityManager sm){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(sm);
//配置登录页面
bean.setLoginUrl("/login");
//配置权限页面
bean.setUnauthorizedUrl("/noPower");
//配置权限的map
HashMap<String, String> map = new HashMap<String, String>();

//必须登录才能访问
map.put("/index", "authc");
//设置访问用户管理业页面需要userInforList权限
map.put("/userInfo/list", "perms[userInforList]");
//设置访问用户管理新增页面需要userInforAdd权限
map.put("/userInfo/add", "perms[userInforAdd]");
////设置访问用户管理修改页面需要admin角色
map.put("/userInfo/Update", "roles[admin]");
bean.setFilterChainDefinitionMap(map);
return bean;
}


8 与授权相关的过滤器

perms权限授权过滤器,验证用户是否拥有所有权限

例如: /emp/filedownPage.do=perms[自定义权限参数]

Roles角色授权过滤器,验证用户是否拥有所有角色

例如: /emp/filedownPage.do=roles[自定义角色参数]

springboot中 shiro标签的使用

1 首先强调一下 角色和权限标签的使用和配置类中配置的角色和权限没有关系,只和reaml类中

的授权有关系

2 在要授权的html页面,把html标签改成

1
2
3
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

3 Shiro标签 在springboot中用法

权限标签写法 ,userInforList, roleInfoList 是自定义权限参数

一:只有拥有userInforList权限才能访问:
shiro:hasPermission=”userInforList”

二: 拥有userInforLis和roleInfoList 任意一个权限才能访问:shiro:hasAnyPermissions=”userInforList,roleInfoList”

三: 拥有userInforLis和roleInfoList 所有权限才能访问:
shiro:hasAllPermissions=”userInforList,roleInfoList”

四: 没有roleInfoList权限才能访问
shiro: lacksPermission =” roleInfoList “

角色标签写法 ,admin和vip 是自定义角色参数

一:只有拥有admin角色才能访问:
shiro:hasRole=”admin”

二: 拥有admin和vip任意一个角色才能访问:

shiro:hasAnyRoles=”admin,vip”
三: 拥有admin和vip 所有角色才能访问:
shiro:hasAllRoles=”admin,vip”
四: 没有admin 角色才能访问
shiro: lacksRole =”admin”

案例演示

用户标签写法

1
shiro:principal="username"   

例一:配置访问用户管理页面需要 用户拥有userInfoList权限,配置如下

1
2
3
4
5
6
<li  shiro:hasPermission="userInforList">
<a _href="/userInfo/list">
<i class="iconfont">&#xe6a7;</i>
<cite>用户管理</cite>
</a>
</li >

例二:配置访问用户管理修改页面需要 用户拥有admin角色,配置如下

1
2
3
<a  shiro:hasRole="admin" title="编辑"  onclick="update(this)" href="javascript:;">
<i class="layui-icon">&#xe642;</i>
</a>

例三:配置访问拥有admin角色可以看到咨询,没有admin角色可以看到图片,配置如下

1
2
3
4
5
6
<dd shiro:hasRole="admin">
<a onclick="x_admin_show('资讯','http://www.baidu.com')"><i class="iconfont">&#xe6a2;</i>资讯</a>
</dd>
<dd shiro:lacksRole="admin" >
<a onclick="x_admin_show('图片','http://www.baidu.com')"><i class="iconfont">&#xe6a8;</i>图片</a>
</dd>
其他文章
cover
Thymeleaf
  • 25/09/27
  • 15:00
  • 1k
  • 5
目录导航 置顶
  1. 1. shiro介绍
  2. 2. 环境搭建
  3. 3. shiro认证
  4. 4. shiro授权
    1. 4.1. 授权实现思路
  5. 5. springboot中 shiro标签的使用
    1. 5.1. 案例演示