一、常见的权限控制方式
1、url拦截权限控制:基于过滤器实现的拦截
2、方法注解权限控制:基于代理实现的拦截
二、项目中导入权限模块相关实体
1、菜单
package com.itheima.bos.domain.system;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* @description:菜单
*/
@Entity
@Table(name = "T_MENU")
public class Menu {
@Id
@GeneratedValue
@Column(name = "C_ID")
private int id;
@Column(name = "C_NAME")
private String name; // 菜单名称
@Column(name = "C_PAGE")
private String page; // 访问路径
@Column(name = "C_PRIORITY")
private Integer priority; // 优先级
@Column(name = "C_DESCRIPTION")
private String description; // 描述
@ManyToMany(mappedBy = "menus")
private Set<Role> roles = new HashSet<Role>(0);
@OneToMany(mappedBy = "parentMenu")
private Set<Menu> childrenMenus = new HashSet<Menu>();
@ManyToOne
@JoinColumn(name = "C_PID")
private Menu parentMenu;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public Set<Menu> getChildrenMenus() {
return childrenMenus;
}
public void setChildrenMenus(Set<Menu> childrenMenus) {
this.childrenMenus = childrenMenus;
}
public Menu getParentMenu() {
return parentMenu;
}
public void setParentMenu(Menu parentMenu) {
this.parentMenu = parentMenu;
}
}
2、权限
package com.itheima.bos.domain.system;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/**
* @description:权限名称
*/
@Entity
@Table(name = "T_PERMISSION")
public class Permission {
@Id
@GeneratedValue
@Column(name = "C_ID")
private int id;
@Column(name = "C_NAME")
private String name; // 权限名称
@Column(name = "C_KEYWORD")
private String keyword; // 权限关键字,用于权限控制
@Column(name = "C_DESCRIPTION")
private String description; // 描述
@ManyToMany(mappedBy = "permissions")
private Set<Role> roles = new HashSet<Role>(0);
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
3、角色
package com.itheima.bos.domain.system;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/**
* @description:角色
*/
@Entity
@Table(name = "T_ROLE")
public class Role {
@Id
@GeneratedValue
@Column(name = "C_ID")
private int id;
@Column(name = "C_NAME")
private String name; // 角色名称
@Column(name = "C_KEYWORD")
private String keyword; // 角色关键字,用于权限控制
@Column(name = "C_DESCRIPTION")
private String description; // 描述
@ManyToMany(mappedBy = "roles")
private Set<User> users = new HashSet<User>(0);
@ManyToMany
@JoinTable(name = "T_ROLE_PERMISSION", joinColumns = {
@JoinColumn(name = "C_ROLE_ID", referencedColumnName = "C_ID") }, inverseJoinColumns = {
@JoinColumn(name = "C_PERMISSION_ID", referencedColumnName = "C_ID") })
private Set<Permission> permissions = new HashSet<Permission>(0);
@ManyToMany
@JoinTable(name = "T_ROLE_MENU", joinColumns = {
@JoinColumn(name = "C_ROLE_ID", referencedColumnName = "C_ID") }, inverseJoinColumns = {
@JoinColumn(name = "C_MENU_ID", referencedColumnName = "C_ID") })
private Set<Menu> menus = new HashSet<Menu>(0);
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Set<Permission> getPermissions() {
return permissions;
}
public void setPermissions(Set<Permission> permissions) {
this.permissions = permissions;
}
public Set<Menu> getMenus() {
return menus;
}
public void setMenus(Set<Menu> menus) {
this.menus = menus;
}
}
4、用户
package com.itheima.bos.domain.system;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/**
* @description:后台用户
*/
@Entity
@Table(name = "T_USER")
public class User {
@Id
@GeneratedValue
@Column(name = "C_ID")
private int id; // 主键
@Column(name = "C_BIRTHDAY")
private Date birthday; // 生日
@Column(name = "C_GENDER")
private String gender; // 性别
@Column(name = "C_PASSWORD")
private String password; // 密码
@Column(name = "C_REMARK")
private String remark; // 备注
@Column(name = "C_STATION")
private String station; // 状态
@Column(name = "C_TELEPHONE")
private String telephone; // 联系电话
@Column(name = "C_USERNAME", unique = true)
private String username; // 登陆用户名
@Column(name = "C_NICKNAME")
private String nickname; // 真实姓名
@ManyToMany
@JoinTable(name = "T_USER_ROLE", joinColumns = {
@JoinColumn(name = "C_USER_ID", referencedColumnName = "C_ID") }, inverseJoinColumns = {
@JoinColumn(name = "C_ROLE_ID", referencedColumnName = "C_ID") })
private Set<Role> roles = new HashSet<Role>(0);
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getStation() {
return station;
}
public void setStation(String station) {
this.station = station;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
5、启动项目,自动建表
三、apache shiro框架简介
1、官网
http://shiro.apache.org/
2、shiro 4大核心功能
3、shiro框架认证代码调用流程
Application Code:应用程序代码,由开发人员编写的代码
Subject:由shiro框架提供,代表当前用户对象
SecurityManager:安全管理器,由shiro框架提供,负责管理所有的Realm
Realm:安全数据桥,类似于DAO,操作权限相关的数据的
四、基于shiro框架实现后台系统的认证操作
1、在coomon-parent的pom.xml中导入shiro的jar包坐标
2、在bos_meanagement_web的web.xml中配置spring使用shiro的过滤器
注意:该过滤器一定要配置在struts2的过滤器之前
<!-- 配置spring提供的shiro的过滤器,用于整合shiro框架的。注意:该过滤器一定要放在struts2过滤器之前 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、在spring配置文件中注册shiroFilter
<!-- 注册shiro框架的bean(过滤器) ,作用是创建shiro框架相关的一些过滤器,每个过滤器进行不同的权限校验 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 注入shiro框架核心对象,安全管理器 -->
<property name="securityManager" ref="securityManager" />
<!--
private String loginUrl; 登录页面
private String successUrl; 录成功后跳转页面
private String unauthorizedUrl;权限不足时的提示页面 -->
<property name="loginUrl" value="/login.html" />
<property name="successUrl" value="/index.html" />
<property name="unauthorizedUrl" value="/unauthorized.html" />
<!-- 指定URL拦截规则 -->
<property name="filterChainDefinitions">
<!--
authc:代表shiro框架提供的一个过滤器,这个过滤器用于判断当前用户是否已经完成认证,
如果当前用户已经认证,就放行,如果当前用户没有认证,跳转到登录页面
anon:代表shiro框架提供的一个过滤器,允许匿名访问 ,即可以不登录访问
**:代表目录下的所有文件及子目录
-->
<value>
/css/* = anon
/images/* = anon
/js/** = anon
/validatecode.jsp* = anon
/userAction_login.action = anon
/** = authc
</value>
</property>
</bean>
<bean id="bosRealm" class="com.itheima.bos.shiro.BosRealm" />
<!-- 注册安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm" />
</bean>
4、调整登录页面
5、创建用户登录的Action动作类
package com.itheima.bos.web.action;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.struts2.ServletActionContext;
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 com.itheima.bos.domain.system.User;
import com.itheima.bos.web.action.common.CommonAction;
/**
* 用户动作类
* @author Administrator
*
*/
@Controller
@Namespace("/")
@Scope("prototype")
@ParentPackage("struts-default")
public class UserAction extends CommonAction<User> {
//定义变量,接收验证码
private String checkcode;
public void setCheckcode(String checkcode) {
this.checkcode = checkcode;
}
/**
* 基于shiro框架实现后台系统认证
*/
@Action(value="userAction_login",results={
@Result(name="home", type="redirect", location="/index.html"),
@Result(name="login", type="redirect", location="/login.html")
})
public String login(){
//从session中获取生成的验证码
String validatecode = (String) ServletActionContext.getRequest().getSession().getAttribute("key");
//判断输入的验证和和生成的验证码是否一致
if(StringUtils.isNotBlank(validatecode) && StringUtils.isNotBlank(checkcode) && validatecode.equals(checkcode)){
//输入的验证码正确,使用shiro进行认证操作
//获取当前用户对象
Subject subject = SecurityUtils.getSubject();
//封装用户名密码令牌
AuthenticationToken token = new UsernamePasswordToken(getModel().getUsername(),getModel().getPassword());
try {
subject.login(token);
User user = (User) subject.getPrincipal();
ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);
return "home";
} catch (Exception e) {
e.printStackTrace();
return LOGIN;
}
}else{
return LOGIN;
}
}
}
6、编写认证授权的realm
package com.itheima.bos.shiro;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.itheima.bos.dao.UserDao;
import com.itheima.bos.domain.system.User;
/**
* 用户认证授权的方法
* @author Administrator
*
*/
public class BosRealm extends AuthorizingRealm {
@Autowired
private UserDao dao;
/**
* 认证的方法
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
UsernamePasswordToken uptoken = (UsernamePasswordToken) token;
//获取用户输入的用户名密码
String username = uptoken.getUsername();
//通过用户名查询用户信息
User user = dao.findByUsername(username);
if(user == null){
//没有查询到用户数据
return null;
}else{
//进行密码比较
//构造简单认证对象,参数1:用户对象,参数2:数据库中的密码,参数3:realm域名字
AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(),this.getName());
return info;
}
}
/**
* 授权的方法
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
return null;
}
}
7、编写用户的Dao方法
package com.itheima.bos.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.itheima.bos.domain.system.User;
public interface UserDao extends JpaRepository<User, Integer> {
public User findByUsername(String username);
}