① 自己写权限框架
② Spring Security (使用复杂, 依赖 Spring )
③ Apache Shiro (更轻量, 使用更简单, 并不完全依赖 spring,可以独立使用 )
代码:
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
shiroFilter
/*
代码:
/login.html* = anon
/user_login.action* = anon
/validatecode.jsp* = anon
/css/** = anon
/js/** = anon
/images/** =anon
/services/** = anon
/pages/base/courier.html* = perms[courier:list]
/pages/base/area.html* = roles[base]
/** =authc
※-->过滤器:
①anon 未认证可以访问
②authc 认证后可以访问
③perms 需要特定权限才能访问
④roles 需要特定角色才能访问
⑤user 需要特定用户才能访问
⑥port 需要特定端口才能访问
⑦reset 根据指定 HTTP 请求访问才能访问
⑧perms[courier:list]:用于用户权限控制,后面会有写到.
BOS管理系统 登陆页面
员工登录
package cn.itcast.bos.web.action.base.system;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import cn.itcast.bos.system.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class UserAction extends ActionSupport implements ModelDriven {
private User user = new User();
@Override
public User getModel() {
return user;
}
@Action(value = "user_login", results = {
@Result(name = "login", type = "redirect", location = "login.html"),
@Result(name = "success", type = "redirect", location = "index.html") })
public String login() {
//基于Shiro实现登录
Subject subject = SecurityUtils.getSubject();
//用户名和密码信息
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
try {
subject.login(token);
//登录成功,将用户信息保存到session当中
return SUCCESS;
} catch (AuthenticationException e) {
//登录失败
e.printStackTrace();
return LOGIN;
}
}
//用户推出登录
@Action(value="user_logout",results={@Result(name="success",type="redirect",location="login.html")})
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return SUCCESS;
}
}
①将自定义 Realm 注入安全管理器 SecurityManager 当中
②Realm
package cn.itcast.bos.realm;
import java.util.List;
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.UsernamePasswordToken;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.itcast.bos.service.base.system.PermissionService;
import cn.itcast.bos.service.base.system.RoleService;
import cn.itcast.bos.service.base.system.Userservice;
import cn.itcast.bos.system.Permission;
import cn.itcast.bos.system.Role;
import cn.itcast.bos.system.User;
// 自定义Realm ,实现安全数据 连接
@Service("bosRealm")
public class BosRealm extends AuthorizingRealm {
@Autowired
private Userservice userService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
@Override
// 认证...
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println("shiro 认证管理... ");
// 转换token
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
// 根据用户名 查询 用户信息
User user = userService.findByUsername(usernamePasswordToken
.getUsername());
if (user == null) {
// 用户名不存在
// 参数一: 期望登录后,保存在Subject中信息
// 参数二: 如果返回为null 说明用户不存在,报用户名
// 参数三 :realm名称
return null;
} else {
// 用户名存在
// 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
// 如果密码一致 登录成功, 如果密码不一致 报密码错误异常
return new SimpleAuthenticationInfo(user, user.getPassword(),
getName());
}
}
}
红色:错误异常请参考我的博客"最权威正解Submitted credentials for token [xxx]] did not match the expected credentials."这篇文章
③Service和Dao代码
package cn.itcast.bos.service.base.system;
import cn.itcast.bos.system.User;
public interface Userservice {
public User findByUsername(String username);
}
package cn.itcast.bos.service.base.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.itcast.bos.dao.base.system.UserRepository;
import cn.itcast.bos.service.base.system.Userservice;
import cn.itcast.bos.system.User;
@Service
@Transactional
public class UserServiceImpl implements Userservice{
@Autowired
private UserRepository userRepository;
@Override
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
package cn.itcast.bos.dao.base.system;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import cn.itcast.bos.system.User;
@Repository
public interface UserRepository extends JpaRepository{
public User findByUsername(String username);
}
菜单,权限,角色,用户
①用户:每个用户属于一个角色
②每个角色有相应的权限,还有对应的菜单
完整的Realm(包括认证和授权)的代码:
package cn.itcast.bos.realm;
import java.util.List;
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.UsernamePasswordToken;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.itcast.bos.service.base.system.PermissionService;
import cn.itcast.bos.service.base.system.RoleService;
import cn.itcast.bos.service.base.system.Userservice;
import cn.itcast.bos.system.Permission;
import cn.itcast.bos.system.Role;
import cn.itcast.bos.system.User;
// 自定义Realm ,实现安全数据 连接
@Service("bosRealm")
public class BosRealm extends AuthorizingRealm {
@Autowired
private Userservice userService; //用户
@Autowired
private RoleService roleService;//角色
@Autowired
private PermissionService permissionService;//权限名称
@Override
// 认证...
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println("shiro 认证管理... ");
// 转换token
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
// 根据用户名 查询 用户信息
User user = userService.findByUsername(usernamePasswordToken
.getUsername());
if (user == null) {
// 用户名不存在
// 参数一: 期望登录后,保存在Subject中信息
// 参数二: 如果返回为null 说明用户不存在,报用户名
// 参数三 :realm名称
return null;
} else {
// 用户名存在
// 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
// 如果密码一致 登录成功, 如果密码不一致 报密码错误异常
return new SimpleAuthenticationInfo(user, user.getPassword(),
getName());
}
}
@Override
// 授权...
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
System.out.println("shiro 授权管理...");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 根据当前登录用户 查询对应角色和权限
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
// 调用业务层,查询角色
List roles = roleService.findByUser(user);
for (Role role : roles) {
authorizationInfo.addRole(role.getKeyword());
}
// 调用业务层,查询权限
List permissions = permissionService.findByUser(user);
for (Permission permission : permissions) {
authorizationInfo.addStringPermission(permission.getKeyword());
}
return authorizationInfo;
}
}
授权:将用户对应的权限查询出
未完待续========================================================!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!