一般需要4张基础表和3张对应关系表。
菜单表 对应角色关系用Set表示:
/**
* 菜单
*/
public class Menu implements Serializable {
private Integer id;
private String name; //菜单名称
private String linkUrl; //访问路径
private String path; //菜单项对应的路由路径
private Integer priority; //优先级排序
private String description; //描述
private String icon; //图标
private Set<Role> roles = new HashSet<Role>(0); //角色集合
private List<Menu> children = new ArrayList<Menu>(); //子菜单集合
private Integer parentMenuId; //父菜单Id
}
权限表 对应角色关系用Set表示:
/**
* 权限
*/
public class Permission implements Serializable {
private Integer id;
private String name;
private String keyword;
private String description;
private Set<Role> roles = new HashSet<Role>(0);
}
用户表 对应角色关系用Set表示:
/**
* 用户
*/
public class User implements Serializable {
private Integer id;
private Date birthDay; //生日
private String gender; //性别
private String username; //用户名。唯一
private String password; //密码
private String remark; //备注
private String station; //状态
private String telephone; //联系电话
private Set<Role> roles = new HashSet<Role>(0); //对应角色集合
}
角色表 对应用户,权限和菜单关系用Set表示:
/**
* 角色
*/
public class Role implements Serializable {
private Integer id;
private String name; //角色名称
private String keyword; //角色关键字,用于权限控制
private String description; //描述
private Set<User> users = new HashSet<User>(0);
private Set<Permission> permissions = new HashSet<Permission>(0);
private LinkedHashSet<Menu> menus = new LinkedHashSet<Menu>(0);
}
附建表语句:
/*
Navicat MySQL Data Transfer
Source Server : xuyu
Source Server Version : 50515
Source Host : localhost:3306
Source Database : authentic
Target Server Type : MYSQL
Target Server Version : 50515
File Encoding : 65001
Date: 2021-06-16 23:08:42
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for t_menu
-- ----------------------------
DROP TABLE IF EXISTS `t_menu`;
CREATE TABLE `t_menu` (
`id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`linkUrl` varchar(255) DEFAULT NULL,
`path` varchar(255) DEFAULT NULL,
`priority` varchar(255) DEFAULT NULL,
`icon` varchar(255) DEFAULT NULL,
`desc` varchar(255) DEFAULT NULL,
`parentMenuId` int(11) DEFAULT NULL,
`level` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_menu
-- ----------------------------
INSERT INTO `t_menu` VALUES ('1', '预约管理', 'ordersettinglist.html', '/3-1', null, null, null, null, '1');
INSERT INTO `t_menu` VALUES ('2', '权限管理', 'permission.html', '/6-1', null, null, null, '1', '1');
INSERT INTO `t_menu` VALUES ('3', '菜单管理', 'menu.html', '/6-1', null, null, null, null, '2');
-- ----------------------------
-- Table structure for t_permission
-- ----------------------------
DROP TABLE IF EXISTS `t_permission`;
CREATE TABLE `t_permission` (
`id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`keyword` varchar(255) DEFAULT NULL,
`desc` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_permission
-- ----------------------------
INSERT INTO `t_permission` VALUES ('1', '新增检查项', 'CHECKITEM_ADD', null);
INSERT INTO `t_permission` VALUES ('2', '删除检查项', 'CHECKITEM_DELETE', null);
-- ----------------------------
-- Table structure for t_role
-- ----------------------------
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
`id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`keyword` varchar(255) DEFAULT NULL,
`desc` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_role
-- ----------------------------
INSERT INTO `t_role` VALUES ('1', '管理员', 'ROLE_ADMIN', null);
INSERT INTO `t_role` VALUES ('2', '用户', 'ROLE_USER', null);
-- ----------------------------
-- Table structure for t_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `t_role_menu`;
CREATE TABLE `t_role_menu` (
`role_id` int(11) DEFAULT NULL,
`menu_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_role_menu
-- ----------------------------
-- ----------------------------
-- Table structure for t_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `t_role_permission`;
CREATE TABLE `t_role_permission` (
`role_id` int(11) DEFAULT NULL,
`permission_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_role_permission
-- ----------------------------
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) DEFAULT NULL,
`birthday` varchar(255) DEFAULT NULL,
`gender` varchar(255) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_user
-- ----------------------------
-- ----------------------------
-- Table structure for t_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role` (
`user_id` int(11) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_user_role
-- ----------------------------
导入springsecurity pom坐标:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.sercurity.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.sercurity.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.sercurity.version}</version>
</dependency>
spring配置文件:
spring-security.xml
需要在先springmvc中导入:<import resource="spring-security.xml"></import>
<beans>
<!--配置那些资源匿名可以访问(不登录也可以访问)-->
<!--<security:http security="none" pattern="/pages/**"></security:http>-->
<security:http security="none" pattern="/login.html"></security:http>
<security:http security="none" pattern="/css/**"></security:http>
<security:http security="none" pattern="/img/**"></security:http>
<security:http security="none" pattern="/js/**"></security:http>
<security:http security="none" pattern="/plugins/**"></security:http>
<!--auto-config自动配置,如果设置为true,表示自动应用一些默认配置,比如框架会提供一个默认的登录页面
use-expressions 是否使用表达式-->
<security:http auto-config="true" use-expressions="true">
<!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问-->
<security:headers>
<security:frame-options policy="SAMEORIGIN"></security:frame-options>
</security:headers>
<!--配置拦截规则,/**表示拦截所有请求-->
<!--pattern:描述拦截规则-->
<!--access:指定所需访问角色或者访问权限-->
<security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"></security:intercept-url>
<!--只要认证通过节能访问-->
<!--<security:intercept-url pattern="/index.jsp" access="isAuthenticated()" />-->
<!--<security:intercept-url pattern="/a.html" access="isAuthenticated()" />-->
<security:intercept-url pattern="/pages/**" access="isAuthenticated()" />
/*********以下可以通过注解设置*************************/
<!--拥有add权限就能访问-->
<security:intercept-url pattern="/b.html" access="hasAuthority('add')" />
<!--拥有ROLE_ADMIN角色节能访问c.htmlyemian-->
<security:intercept-url pattern="/c.html" access="hasRole('ROLE_ADMIN')" />
<!--如果我们要使用自己指定的页面作为登录页面,必须配置登录表单-->
<security:form-login login-page="/login.html"
username-parameter="username"
password-parameter="password"
login-processing-url="/login.do"
default-target-url="/index.html" 登录成功默认页面
authentication-failure-url="/login.html"/> 登录失败页面
<!--csrf:对应CsrfFilter过滤器 disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁止-->
<security:cerf disabled="true"></security:cerf>
<!--logout:退出登录-->
<!--logout-url:退出登录操作对应的请求路径-->
<!--logout-success-url:退出登陆后的跳转页面-->
<security:logout logiut-url="/logout.do" logout-success-url="/login.html" invalidate-session="true" />
</security:http>
<!--配置认证管理器-->
<security:authentication-manager>
<!--配置认证提供者-->
<security:authentication-provider user-service-ref="userService">
<!--<!–配置一个用户,后期需要从数据库查询用户–>-->
<!--<security:user-service>-->
<!--<security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"/>-->
<!--</security:user-service>-->
<!--指定密码进行加密的对象-->
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<bean id="userService" class="com.xuyu.service.SpringSecurityUserService"></bean>
<!--配置密码加密对象-->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoding"/>
<!--开启spring注解-->
<context:annotation-config></context:annotation-config>
</beans>
只需要Service实现security框架提供的UserDetailsService接口:
//实现security框架提供的接口
@Compoment
public class SpringSecurityUserService implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
//模拟数据库中的用户信息
public static Map<String, User> map = new HashMap<String,User>();
public void initUserData(){
User user = new User();
user.setUsername("admin");
user.setPassword(passwordEncoder.encode("admin")); //加密
User user1 = new User();
user1.setUsername("yuangong");
user1.setPassword("2123");
map.put(user.getUsername(),user1);
map.put(user1.getUsername(),user1);
}
//根据用户名查询用户信息
public UserDetals loadUserByUsername(String username){
System.out.println("用户输入的用户名为"+username);
//根据用户名查询数据库获得用户信息(包含数据库中存储的密码信息)
User user = map.get(username);
if(user == null){
//用户不存在
return null;
}else {
//将用户信息返回给框架
//框架会进行密码比对(页面提交的密码和数据中查询的密码进行比对)
ArrayList<GrantedAuthority> list = new ArrayList<GrantedAuthority>(); //授权,后期需要查询数据库
list.add(new SimpleGrantedAuthority("permission_A")); //授权
list.add(new SimpleGrantedAuthority("permission_B"));
if(username.equals("admin")) { //只有admin才能登录
list.add(new SimpleGrantedAuthority("ROLE_ADMIN")); //授予角色
}
security.core.userdetails.User securityUser = new security.core.userdetails.User(username,user.getPassword(),list);
return securityUser;
}
}
}
基于方法注解方式进行权限设置:
spring-security.xml 添加注解开关
<!--开启spring注解-->
<context:annotation-config></context:annotation-config>
<mvc:anotation-driven></mvc:anotation-driven>
<context:component-scan base-package="com.xuyu.controller"></context:component-scan>
<!--开启方法注解方式权限控制-->
<security:global-method-security pre-post-annotations="enable" />
编写测试类
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/add")
@PreAuthorize("hasAuthority('add')") //调用此方法要求当前用户必须具有add权限
public String add(){
System.out.println("test");
return "success";
}
@RequestMapping("/delete")
@PreAuthorize("hasRole('ROLE_ADMIN')") //调用此方法要求当前用户必须具有ROLE_ADMIN角色
public String delete(){
System.out.println("delete test");
return "success";
}
}
从数据库获取角色和权限信息版本:
实现spring security登录鉴权接口:
//此方法框架会在用户登录时调用
public class SpringSecurityUserService implements UserDetailsService {
//使用dubbo通过网络远程调用服务提供方获取数据库中的信息
@Autowired
private UserSerivice userSerivice;
//根据用户名查询数据库获取用户信息
public UserDeails loadUserByUsername(String username){
User user = userSerivice.findByUsername(username);
if(user == null){
return null;
}
//动态为当前用户授权
List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
Set<Role> roles = user.getRoles();
for (Role role : roles) {
//遍历角色集合,为用户授予角色
list.add(new SimpleGrantedAuthority(role.getKeyword()));
Set<Permission> permissions = role.getPermissions();
for (Permission permission : permissions) {
//遍历权限集合,为用户授权
list.add(new SimpleGrantedAuthority(permission.getKeyword()));
}
}
org.springframework.security.core.userdetails.User securityUser = new org.springframework.security.core.userdetails.User(username,user.getPassword(),list);
return securityUser;
}
}
@Service
@Transactional
public class UserSeriviceImpl implements UserSerivice {
@Autowired
private UserDao userDao;
@Autowired
private RoleDao roleDao;
@Autowired
private PermissionDao permissionDao;
//根据用户名查询数据库获取用户信息,同时需要查询查询角色关联的权限信息
public User findByUsername(String username){
User user = userDao.findByUsername(username); //查询用户基本信息。不包括用户的角色
if(user == null){
return null;
}
Integer userId = user.getId();
//根据用户Id查询对应的角色
Set<Role> roles = roleDao.findByUserId(userId);
for (Role role : roles) {
Integer roleId = role.getId();
//根据角色Id查询关联的权限
Set<Permission> permissions = permissionDao.findByRolreId(roleId);
role.setPermissions(permissions); //角色关联权限
}
user.setRoles(roles); //让用户关联角色
return user;
}
}
UserDao.xml
<mapper namespace="com.xuyu.dao.UserDao">
<select id="findByUsername" parameterType="String" resultType="com.xuyu.pojo.User">
select * from t_user where username = ${username}
</select>
</mapper>
RoleDao.xml:
<mapper namespace="com.xuyu.dao.RoleDao">
<!--根据用户Id查询关联的角色-->
<select id="findByUserId" parameterType="int" resultType="com.xuyu.pojo.Role">
select a.* from t_role a,t_user_role b where a.id = b.role_id and b.user_id = #{user_id}
</select>
</mapper>
PermissionDao.xml
<mapper namespace="com.xuyu.dao.PermissionDao">
<!--根据用户Id查询关联的角色-->
<select id="findByRoleId" parameterType="int" resultType="com.xuyu.pojo.Permission">
select a.* from t_permission a,t_role_permission b where a.id = b.permission_id and b.roleid = #{role_id}
</select>
</mapper>