登录页面:
LoginController:
@GetMapping
public ModelAndView toLogin() {// 跳转登录页面ModelAndView mv = new ModelAndView("login");return mv;
}@PostMapping()
public ModelAndView login(User user, HttpServletRequest request) {ModelAndView mv = new ModelAndView();//得到subjectSubject subject = SecurityUtils.getSubject();//创建用户名和MD5加密过的密码身份验证TokenUsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), new Md5Hash(user.getPassword()).toString());try {subject.login(token);// 登录,即用户身份认证} catch (AuthenticationException e) {// 登录失败,跳转登录页面log.error("用户登录失败", e);mv.addObject("msg", "用户名或密码错误");mv.setViewName("login");return mv;}if (subject.isAuthenticated()) {// 登录成功,保存用户信息,跳转首页request.getSession().setAttribute("user", user.getUserName());mv.setViewName("redirect:/user.do");return mv;} else {log.error("用户登录失败");mv.addObject("msg", "用户名或密码错误");mv.setViewName("login");return mv;}}
登录失败:
登录成功:
系统登出操作
上一节在xml配置了shiro登出过滤器,它的作用是在用户退出系统时,清空缓存等操作。解决更新用户权限后不立马起作用的小问题。
登出按钮如下,不需要写loginOut对应的Controller,shiro自动拦截,然后跳转登录界面,详见上一节配置
<li class="xxx"><a href="loginOut"> 退出 </a></li>
shiro授权常用方式一:基于注解
注解 | 意义 | 案例 |
---|---|---|
@RequiresAuthentication | 验证用户是否登录 | |
@RequiresUser | 当前用户已经验证过了或则记住我了 | |
@RequiresGuest | 是否是游客身份 | |
@RequiresRoles | 判断subject中有aRoleName角色才可以访问方法someMethod | @RequiresRoles({“admin”}) |
@RequiresPermissions | 需要拥有权限 | @RequiresPermissions({“file:read”, “write:aFile.txt”} ) |
Controller方法上面添加相应注解
@DeleteMapping(value="/{id}")
@ResponseBody
@RequiresRoles({"admin"})
public ResponseEntity<Integer> delUser(@PathVariable("id")int id) {try{userService.delUser(id);}catch(Exception e){log.error("删除用户失败",e);return new ResponseEntity<Integer>(HttpStatus.INTERNAL_SERVER_ERROR);}return new ResponseEntity<Integer>(Common.common_success,HttpStatus.OK);}
shiro授权常用方式二:jsp页面授权,基于<shiro>标签
导入<shiro>标签库:<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>
标签名称 |
标签条件(均是显示标签内容) |
<shiro:authenticated> |
登录之后 |
<shiro:notAuthenticated> |
不在登录状态时 |
<shiro:guest> |
用户在没有RememberMe时 |
<shiro:user> |
用户在RememberMe时 |
<shiro:hasAnyRoles name="abc,123" > |
在有abc或者123角色时 |
<shiro:hasRole name="abc"> |
拥有角色abc |
<shiro:lacksRole name="abc"> |
没有角色abc |
<shiro:hasPermission name="abc"> |
拥有权限资源abc |
<shiro:lacksPermission name="abc"> |
没有abc权限资源 |
<shiro:principal> |
显示用户身份名称 |
1:实现粗粒度权限控制,通过判断用户是否有角色/权限,控制左侧菜单栏的显示和隐藏
<shiro:hasPermission name="systemUser"><i class="fa fa-sitemap"></i> 用户中心 <shiro:hasPermission name="userManager"><a href="user.do">用户管理</a></shiro:hasPermission> <shiro:hasPermission name="roleManager"><a href="role.do">角色管理</a></shiro:hasPermission>
</shiro:hasPermission>
2:实现细粒度权限控制,通过判断用户是否有角色/权限,决定是否显示删除/编辑按钮
<shiro:hasPermission name="roleManagerDelete"><button id="del" onclick="del(${role.id})">删除</button>
</shiro:hasPermission>
<shiro:hasPermission name="roleManagerUpdate"><button id="upd" onclick="upd(${role.id})">修改</button>
</shiro:hasPermission>
注意1:调试过程中,可能会遇到自定义的DbRealm中授权方法进不去,这是因为,你在跳转的方法上面没有使用shiro授权注解,同时在要跳转的页面没有使用<shiro>标签授权。必须有授权行为,才能进入授权方法。
注意2:实践过程中,可能需要在js中拼接<shiro>标签,生成html代码,这是这样生成的<shiro>标签不起作用
例如:
var htm = '';
htm += '<shiro:hasPermission name="roleManagerDelete">';
htm += '<button>删除</button>';
htm += '</shiro:hasPermission>';
return htm;
解决思路:先在页面通过<shiro>标签生成一个变量,js根据这个变量来判断是否需要拼接删除按钮的html
<!-- jsp代码 -->
<shiro:hasPermission name="roleManagerDelete"><input type="text" id="isDelete" hidden="true" value="true">
</shiro:hasPermission><!-- js代码 -->
var htm = '';
if($("#isDelte").val() == "t"){htm += '<button>删除</button>';
}
return htm;
上一节:spring整合shiro