概述
准备数据
CREATE TABLE `user` (
`name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `role` (
`name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `privilege` (
`name` varchar(255) NOT NULL,
`uri` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_role` (
`user_name` varchar(255) NOT NULL,
`role_name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `role_privilege` (
`role_name` varchar(255) NOT NULL,
`privilege_name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
插入数据
INSERT INTO `user` VALUES ('u1');
INSERT INTO `user` VALUES ('u2');
INSERT INTO `role` VALUES ('r1');
INSERT INTO `role` VALUES ('r2');
INSERT INTO `role` VALUES ('r3');
INSERT INTO `privilege` VALUES ('p1', '/p1');
INSERT INTO `privilege` VALUES ('p2', '/p2');
INSERT INTO `privilege` VALUES ('p3', '/p3');
INSERT INTO `privilege` VALUES ('p4', '/p4');
INSERT INTO `user_role` VALUES ('u1', 'r1');
INSERT INTO `user_role` VALUES ('u1', 'r2');
INSERT INTO `user_role` VALUES ('u2', 'r2');
INSERT INTO `user_role` VALUES ('u2', 'r3');
INSERT INTO `role_privilege` VALUES ('r1', 'p1');
INSERT INTO `role_privilege` VALUES ('r1', 'p2');
INSERT INTO `role_privilege` VALUES ('r2', 'p2');
INSERT INTO `role_privilege` VALUES ('r2', 'p3');
INSERT INTO `role_privilege` VALUES ('r3', 'p3');
INSERT INTO `role_privilege` VALUES ('r3', 'p4');
此时如果要查询某一个用户对应的角色和权限,sql如下
select
u.name user_name,r.name role_name,p.name privilege_name,p.uri uri
from
user u
INNER JOIN
user_role ur ON u.name = ur.user_name
INNER JOIN
role r on ur.role_name = r.name
INNER JOIN
role_privilege rp on r.name = rp.role_name
INNER JOIN
privilege p on rp.privilege_name = p.name
where
u.name = #{username}
1.通过Filter实现用户登录校验和权限校验
在业务中,只有用户登录了,才能访问服务器中的资源
分析:
-
1.判断是登录后,才能访问的资源
- 是:比如各种接口,比如某些jsp资源,判断用户是否登录
- 否:比如login.jsp,、loginServlet、以及一些css/js文件,直接放行
-
2.判断当前用户是否登录,判断session中是否有user
- 有,用户已经登录,放行.(进行用户权限校验)
- 否.跳转登录页面
(1)用户登录校验
package demo.filter;
import demo.pojo.User;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
// 登录校验
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 获取资源请求路径
String uri = request.getRequestURI();
// 判断当前访问资源,是否是是登录后,才能访问的资源
String contextPath = request.getContextPath();
if (uri.equals(contextPath + "/login.jsp") || uri.equals(contextPath + "/login")
|| uri.startsWith(contextPath + "/css/") || uri.startsWith(contextPath + "/js/")) {
// 在request中添加一个标识,告诉后面的过滤器,直接放行
request.setAttribute("filterPass", true);
filterChain.doFilter(servletRequest, servletResponse);
} else {
// 此资源需要用户登录后才能访问
User user = (User)request.getSession().getAttribute("user");
if(user != null){
//登录了。放行
filterChain.doFilter(servletRequest, servletResponse);
}else{
//没有登录。跳转登录页面(使用重定向或者请求转发都可以实现)
// request.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
HttpServletResponse response = (HttpServletResponse)servletResponse;
response.sendRedirect(contextPath + "/login.jsp");
}
}
}
@Override
public void destroy() {
}
}
xml
<!-- 登录过滤器 -->
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>demo.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
登录页面
package demo.controller;
import demo.mapper.UserMapper;
import demo.pojo.User;
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.RequestParam;
import javax.servlet.http.HttpServletRequest;
@Controller
public class UserController {
@Autowired
private UserMapper userMapper;
// 跳转到users.jsp
@RequestMapping(value = "login")
public String toUsers(@RequestParam("name")String name, HttpServletRequest request) {
User user = userMapper.queryUserByName(name);
request.getSession().setAttribute("user", user);
return "success";
}
// 跳转到users.jsp
@RequestMapping(value = "p1")
public String p1(HttpServletRequest request) {
return "p1";
}
// 跳转到users.jsp
@RequestMapping(value = "p2")
public String p2(HttpServletRequest request) {
return "p2";
}
// 跳转到users.jsp
@RequestMapping(value = "p3")
public String p3(HttpServletRequest request) {
return "p3";
}
// 跳转到users.jsp
@RequestMapping(value = "p4")
public String p4(HttpServletRequest request) {
return "p4";
}
}
(2)通过filter实现权限控制
package demo.filter;
import demo.pojo.Privilege;
import demo.pojo.Role;
import demo.pojo.User;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PrivilegeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
// 登录校验
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 获取标识,判断是否为不需要进行权限校验的资源
Boolean pass = (Boolean)request.getAttribute("filterPass");
if (null == pass || !pass.equals(true)) {
User user = (User)request.getSession().getAttribute("user");
// 判断用户是否有访问此资源的权限
Set<String> uri = new HashSet<>();
List<Role> roles = user.getRoles();
for (Role role : roles) {
List<Privilege> privileges = role.getPrivileges();
for (Privilege privilege : privileges) {
uri.add(request.getContextPath() + privilege.getUri());
}
}
// 用户的所有权限包含当前访问资源的uri
if (uri.contains(request.getRequestURI())){
filterChain.doFilter(servletRequest, servletResponse);
} else {
HttpServletResponse response = (HttpServletResponse)servletResponse;
response.sendRedirect(request.getContextPath() + "/login.jsp");
}
} else {
// 放pass为true时,此资源不用权限校验,直接放行
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void destroy() {
}
}
因为在filter中,我们无法知道请求对应的是哪个controller中的哪个方法,所以我们只能通过用户和uri来进行权限控制
2.通过拦截器实现用户登录校验和权限校验
首先我们看下拦截器的如何被调用的。
Web请求被DispatcherServlet截获后,会调用DispatcherServlet的doDispatcher方法。
当我们访问一个uri,映射器找不到对应的handler时,此时返回的HandlerExecutionChain为null(虽然我们设置的拦截器的路径为/**,拦截所有,但其实拦截器是通过映射器来调用的,只有当映射器找到具体的handler时,才会去找对应的拦截器)
我们在通常情况下,设置DispatcherServlet的url为/,仅处理访问handler的请求,映射器也是如此,它无法去映射到一些静态资源,例如xx.jsp、xx.html、xx.css
也就是说拦截器只能拦截通过映射器找到的handler,映射器无法映射到的资源,它都是不能拦截的,例如xx.jsp、xx.html、xx.css等等
所以在实现用户登录校验时,我们只要关注那些handler(对应的uri)是可以通行的
(1)使用拦截器实现用户登录校验
用户没有登录时,仅能访问/login所对应的handler
package demo.interceptors;
import demo.pojo.User;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String uri = request.getRequestURI();
// 如果是login放行
if (uri.equals(request.getContextPath() + "/login")) {
return true;
} else{
User user = (User)request.getSession().getAttribute("user");
if(user != null){
//登录了。放行
return true;
}else{
//没有登录。跳转登录页面(使用重定向或者请求转发都可以实现)
response.sendRedirect(request.getContextPath() + "/login.jsp");
return false;
}
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
path="/**"表示拦截所有层级的路径
<!-- 注册自定义的拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有请求 -->
<mvc:mapping path="/**"/>
<!-- 自定义拦截器的全路径 -->
<bean class="demo.interceptors.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
(2)使用拦截器实现权限校验
package demo.interceptors;
import demo.pojo.Privilege;
import demo.pojo.Role;
import demo.pojo.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PrivilegeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String uri = request.getRequestURI();
// 如果是login放行
if (uri.equals(request.getContextPath() + "/login")) {
return true;
} else{
//进行权限校验
User user = (User)request.getSession().getAttribute("user");
Set<String> uris = new HashSet<>();
List<Role> roles = user.getRoles();
for (Role role : roles) {
List<Privilege> privileges = role.getPrivileges();
for (Privilege privilege : privileges) {
uris.add(request.getContextPath() + privilege.getUri());
}
}
if (uris.contains(request.getRequestURI())){
return true;
} else {
response.sendRedirect(request.getContextPath() + "/login.jsp");
return false;
}
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
<!-- 注册自定义的拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有请求 -->
<mvc:mapping path="/**"/>
<!-- 自定义拦截器的全路径 -->
<bean class="demo.interceptors.LoginInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- 拦截所有请求 -->
<mvc:mapping path="/**"/>
<!-- 自定义拦截器的全路径 -->
<bean class="demo.interceptors.PrivilegeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
3.总结过滤器和拦截器差别
1.过滤器和拦截器的的触发时机不同,过滤器是进入容器后,但请求进入servlet之前进行预处理的,返回也是在servlet处理完后进行返回的,两者的执行顺序如下图
2.拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。
3.拦截器可以知道请求对应的是哪个handler(哪个Controller中的哪个method),而过滤器是无法知道的
4.过滤器可以拦截所有的资源,拦截器一般只拦截handler
最后
以上就是羞涩招牌为你收集整理的权限设计、用户登录校验的全部内容,希望文章能够帮你解决权限设计、用户登录校验所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复