前言:
如何实现用户授权的,即如何实现不同的用户有不同的权限,访问的资源不同?
不同用户属于不同的角色,不同的角色有不同的权限。
1、数据库如何设计
(1)多个用户可以是同一种角色,一个用户也可以是多种角色如:
角色表:t_role
用户表:t_user
用户角色表:t_user_role
小明和小红是管理员,小强和小张是普通用户;其实这里小明和小红也是普通用户,但管理员权限一般比普通用户多
(2)每一种角色都有多种权限
权限表:t_authority
角色权限表:t_role_authority
注意:此表不设置主键,但role_id设置成非空
管理员什么都能做,普通用户只能看到用户列表,不能进行其它操作
(3)要给t_role和t_authority两个表,分别添加一列角色码和权限码,就是用来描述角色和权限的,角色码和权限码会在用户授权时配置给当前登录成功的用户。
t_role:
t_authority:
2、举例说明
(1)实现目标:管理员登录显示用户列表,且能进行增删改;普通用户登录只显示用户列表,不能进行增删改查;(实现目标很简单,其实只需要角色码或者权限码一方,就能实现这个功能;我这里都用上,熟悉代码)
(2)后台代码
当用户验证完毕后,会自动执行用户授权;用户验证上一篇有详细讲解,这里附上整个代码;
UserRealm.java:
package shiro;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import model.User;
import service.UserService;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//从token获得输入的账号
String userName = token.getPrincipal()+"";
//根据输入的账号到数据库去查找对应的用户
User user = userService.findUserByUserName(userName);
//用户不存在,表明账号不存在,则登录失败
if(user==null){
System.out.println("账号不存在");
throw new UnknownAccountException();
}else{
//否则表明账号存在,判断密码是否正确
/*注册用户时,我们若对密码进行先添加salt盐值后通过MD5加密,最后保存到数据库
*那么在登录时,就需要根据当前输入的密码结合从数据库中取出的user的salt值,再经过
*1024次MD5加密得到的字符串和user的密码进行对比,若相同才代表密码正确
*/
//获得user的salt值
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
//下面一句的作用是先比较账号,肯定相同;然后比较密码,相同则返回authenticationInfo,不同则抛异常
//如果验证成功,最终这里返回的信息authenticationInfo 的值与传入的第一个字段的值相同,这里就是账号
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserName(),user.getPassWord(),salt,getName());
//能执行到这里,说明用户验证成功,记录当前登录进系统的用户
Subject currentUser = SecurityUtils.getSubject();
currentUser.getSession().setAttribute("CURR_USER", user);
return authenticationInfo;
}
}
//用户授权,用户认证成功后,就自动给当前用户进行授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取当前登录进系统的用户
Subject currentUser = SecurityUtils.getSubject();
User user = (User) currentUser.getSession().getAttribute("CURR_USER");
//获取用户的角色码和权限码
Set<String> currRoleCodes = userService.findUserCodesById(user.getId());
Set<String> authorityCodes = userService.findAuthorityCodesById(user.getId());
//为当前用户设置角色和权限,让shiro去管理
SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
simpleAuthorInfo.setRoles(currRoleCodes);
simpleAuthorInfo.setStringPermissions(authorityCodes);
return simpleAuthorInfo;
}
}
UserController.java:
package controller;
import java.util.HashMap;
import java.util.Map;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import model.User;
import service.UserService;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/list")
@ResponseBody
//属于user或者admin之一;修改logical为OR 即可
@RequiresRoles(value={"role:commonUser","role:admin"},logical=Logical.OR)
public Map<String,Object> list(Integer page,Integer rows) {
return userService.findUser(page,rows);
}
@RequestMapping("/save")
@ResponseBody
@RequiresRoles("role:admin")
//或者写下面一句,有这种权限才能做这个事;也可以根据不同情况都写上
@RequiresPermissions("user:add")
public Map<String,Object> save(User user) {
int res = userService.saveUser(user);
Map<String,Object> map = new HashMap<String,Object>();
if(res == 1) {
map.put("code",200);
}else{
map.put("code", 500);
}
return map;
}
@RequestMapping("/del")
@ResponseBody
@RequiresRoles("role:admin")
@RequiresPermissions("user:delete")
public Map<String,Object> del(Integer id) {
int res = userService.delUserById(id);
Map<String,Object> map = new HashMap<String,Object>();
if(res == 1) {
map.put("code",200);
}else{
map.put("code", 500);
}
return map;
}
@RequestMapping("/update")
@ResponseBody
@RequiresRoles("role:admin")
@RequiresPermissions("user:update")
public Map<String,Object> update(User user) {
int res = userService.updateUser(user);
Map<String,Object> map = new HashMap<String,Object>();
if(res == 1) {
map.put("code",200);
}else{
map.put("code", 500);
}
return map;
}
@RequestMapping("/login")
public String Login(User user) {
Subject subject = SecurityUtils.getSubject();
try {
//用token保存输入的账号和密码
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassWord());
//进行用户验证
subject.login(token);
} catch (AuthenticationException e) {
e.printStackTrace();
}
return "redirect:/list.html";
}
}
dao层对应的UserMapper.xml中添加:
<!-- shiro实现用户认证时,要根据输入的账号从数据库获得user -->
<select id="findUserByUserName" resultMap="UserMap">
select * from t_user where user_name=#{userName}
</select>
<!-- shiro实现用户授权时,要获取当前登录用户的角色码 ,权限码-->
<select id="findUserCodesById" resultType="java.lang.String">
SELECT role_code FROM `t_role` r
LEFT JOIN `t_user_role` ur ON r.`id`=ur.`role_id` WHERE ur.`user_id`=#{id}
</select>
<select id="findAuthorityCodesById" resultType="java.lang.String">
SELECT `authority_code` FROM `t_user_role` AS ur,`t_role_authority` AS ra,`t_authority` AS a
WHERE ur.`role_id`=ra.`role_id` AND ra.`authority_id`=a.id AND ur.`user_id`=#{id}
</select>
下一篇:一个完整的权限管理的案例;待续