精华内容
下载资源
问答
  • JAVA实现权限控制

    2020-08-30 11:42:41
    初识别权限 权限无处不在,权限就是限制角色可以访问哪些资源,可以操作哪些资源。 权利与限制:能做与不能做,正确的行使权利,在限定的范围内行使权利,不该看的不看,不该做的不做。...权限控制中,核心.

    初识别权限

    权限无处不在,权限就是限制角色可以访问哪些资源,可以操作哪些资源。

    权利与限制:能做与不能做,正确的行使权利,在限定的范围内行使权利,不该看的不看,不该做的不做。

    RBAC

    • Role-Based Access Control :基于角色的访问控制
    • 权限与角色关联
    • 用户与角色管理

     例如有个用户登录了系统,首先我们根据用户登录的信息判断他是商品管理的角色,然后根据角色信息查询到商品管理角色具有商品分类,商品信息查看的权限,那么该用户就可以访问这些对应的资源。

    权限控制中,核心是角色,角色才是决定你可以访问哪些资源,不关心用户是谁,只关心你的角色是什么。

    用户关联到角色,角色关联到权限,这样就实现了用户拥有了哪些权限。

    权限细分

     数据库的设计:

     实现权限控制有两种方式

     

     

    展开全文
  • 在操作中经常性的要对用户是否登陆进行验证,那么如果要进行验证的...登录页面:Login.jsp//检查是否输入用户名 否则不予提交function check(){var username = document.getElementById("username").value;if(usern...

    在操作中经常性的要对用户是否登陆进行验证,那么如果要进行验证的话,则肯定有大量的代码要不断的判断session是否存在。那么此种代码实际上就可以直接放在过滤器中进行编写。

    登录页面:Login.jsp

    //检查是否输入用户名 否则不予提交

    function check(){

    var username = document.getElementById("username").value;

    if(username==null||""==username){

    alert("请输入用户名");

    return false;

    }

    return true;

    }

    用户登录
    用户名
    密码

    权限控制 用户其实就只有一个入口,即首先进行登录,登录后将信息保存在session中,如果session中没有内容,则无法进入其他页面或进行其他操作。

    点击登录按钮 进入loginServlet将信息保存。

    LoginServlet.java

    package com.org;

    import java.io.IOException;

    import java.io.PrintWriter;

    import javax.servlet.ServletException;

    import javax.servlet.http.HttpServlet;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import javax.servlet.http.HttpSession;

    public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    response.setContentType("text/html;charset=gbk");

    request.setCharacterEncoding("gbk");

    PrintWriter out = response.getWriter();

    String username = request.getParameter("username");

    HttpSession session = request.getSession();

    session.setAttribute("username", username); //用户登录加入到session中

    response.sendRedirect("jsp/success.jsp"); //登录成功 跳入success.jsp

    //测试

    System.out.println("username: "+username);

    out.flush();

    out.close();

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    this.doGet(request, response);

    }

    }

    Filter 拦截器: MyFilter.java

    package com.org;

    import java.io.IOException;

    import java.io.PrintWriter;

    import java.io.UnsupportedEncodingException;

    import javax.servlet.Filter;

    import javax.servlet.FilterChain;

    import javax.servlet.FilterConfig;

    import javax.servlet.ServletException;

    import javax.servlet.ServletRequest;

    import javax.servlet.ServletResponse;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import javax.servlet.http.HttpSession;

    public class MyFilter implements Filter {

    public void destroy() {

    }

    public void doFilter(ServletRequest servletRequest,

    ServletResponse servletResponse, FilterChain filterChain)

    throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) servletRequest;

    HttpSession session = req.getSession();

    String username = (String)session.getAttribute("username");

    if (username != null&&username!="") {

    // 如果现在存在了session,则请求向下继续传递

    filterChain.doFilter(servletRequest, servletResponse);

    } else {

    // 跳转到提示登陆页面

    servletRequest.getRequestDispatcher("/error.jsp").forward(servletRequest, servletResponse);

    }

    }

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    }

    Filter从session中取出数据 看是否已登录,如果session中有内容 则执行 filterChain.doFilter()方法 请求继续向下传递。否则返回登录页面。

    为了测试 还要有一个让其Session失效的类

    InvalidateServlet.java

    package com.org;

    import java.io.IOException;

    import java.io.PrintWriter;

    import javax.servlet.ServletException;

    import javax.servlet.http.HttpServlet;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import javax.servlet.http.HttpSession;

    public class InvalidateServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    response.setContentType("text/html;charset=gbk");

    request.setCharacterEncoding("gbk");

    PrintWriter out = response.getWriter();

    HttpSession session =request.getSession(); //得到session对象

    session.invalidate(); //注销session 使其失效

    //然后跳转到登录页面

    request.getRequestDispatcher("/login.jsp").forward(request, response);

    out.flush();

    out.close();

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    }

    }

    如果在未登录时访问其他页面 则跳转到error.jsp页面

    您还未登录,请先进行登录

    登录成功页面 success.jsp

    欢迎光临

    退出

    此外最好需要几个测试页面

    test1.jsp  test2.jsp 里面随便一些显示内容即可

    配置web.xml实现拦截

    myfilter

    com.org.MyFilter

    myfilter

    /jsp/*

    LoginServlet

    com.org.LoginServlet

    InvalidateServlet

    com.org.InvalidateServlet

    LoginServlet

    /loginServlet

    InvalidateServlet

    /invalidateServlet

    index.jsp

    除login.jsp在webroot目录下  其余jsp页面在jsp文件夹下

    可进行如下方法的测试

    不先进入login.jsp进行登录 访问 http://localhost:8080/filter/jsp/test1.jsp 则提示尚未登录。

    然后进行登录 随便输入一个用户名,再访问test1.jsp 则可以进入 或者关闭浏览器重新打开,还是可以进入

    直至在success.jsp页面中进行注销 。

    0_132376652847J2.gif

    0_1323766533vVtV.gif

    0_1323766536335e.gif

    0_132376654120DR.gif

    展开全文
  • Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、...下面主要讲述一下SpringMVC集成Shiro权限实现登录控制简单封装案例。1.springmvc整合shiro权限,首先需要引入相关的jar包,maven项目中pom.xml文件,...

    Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。下面主要讲述一下SpringMVC集成Shiro权限实现登录控制简单封装案例。

    1.springmvc整合shiro权限,首先需要引入相关的jar包,maven项目中pom.xml文件,新增jar配置依赖,内容如下:

    org.apache.shiro

    shiro-core

    1.2.4

    org.apache.shiro

    shiro-web

    1.2.4

    org.apache.shiro

    shiro-quartz

    1.2.4

    org.apache.shiro

    shiro-spring

    1.2.4

    org.apache.shiro

    shiro-aspectj

    1.2.4

    2.新建AuthenticationFilter.java类文件,具体内容如下:package com.yoodb.core.shiro.filter;

    import java.io.IOException;

    import javax.servlet.ServletRequest;

    import javax.servlet.ServletResponse;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.apache.shiro.SecurityUtils;

    import org.apache.shiro.authc.UsernamePasswordToken;

    import org.apache.shiro.web.filter.PathMatchingFilter;

    import org.apache.shiro.web.util.WebUtils;

    public class AuthenticationFilter extends PathMatchingFilter{

    private String failureUrl;

    private String successUrl;

    @Override

    protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {

    if (SecurityUtils.getSubject().isAuthenticated()) {

    return true;

    }

    HttpServletRequest req = (HttpServletRequest) request;

    HttpServletResponse resp = (HttpServletResponse) response;

    if (isLoginRequest(req)) {

    if ("post".equalsIgnoreCase(req.getMethod())) {

    boolean loginSuccess = login(req);

    if (loginSuccess) {

    redirectToSuccessUrl(req, resp);

    }

    }else {

    saveRequestAndRedirectToLogin(req, resp);

    }

    }

    return true;

    }

    private boolean redirectToSuccessUrl(HttpServletRequest req, HttpServletResponse resp) throws IOException {

    WebUtils.redirectToSavedRequest(req, resp, successUrl);

    return false;

    }

    private void saveRequestAndRedirectToLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException {

    WebUtils.saveRequest(req);

    WebUtils.issueRedirect(req, resp, failureUrl);

    }

    private boolean login(HttpServletRequest req) {

    String username = req.getParameter("username");

    String password = req.getParameter("password");

    try {

    SecurityUtils.getSubject().login(new UsernamePasswordToken(username, password));

    } catch (Exception e) {

    req.setAttribute("shiroLoginFailure", e.getClass());

    return false;

    }

    return true;

    }

    private boolean isLoginRequest(HttpServletRequest req) {

    return pathsMatch(successUrl, WebUtils.getPathWithinApplication(req));

    }

    public String getFailureUrl() {

    return failureUrl;

    }

    public void setFailureUrl(String failureUrl) {

    this.failureUrl = failureUrl;

    }

    public String getSuccessUrl() {

    return successUrl;

    }

    public void setSuccessUrl(String successUrl) {

    this.successUrl = successUrl;

    }

    }

    3.Realm充当Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。添加Realm类,新建UserRealm.java类文件,具体内容如下:package com.yoodb.core.shiro.realm;

    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.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;

    public class UserRealm extends AuthorizingRealm {

    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

    authorizationInfo.setRoles(null);

    authorizationInfo.setStringPermissions(null);

    return authorizationInfo;

    }

    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

    // TODO Auto-generated method stub

    UsernamePasswordToken upToken = (UsernamePasswordToken)token;

    //获得用户名与密码

    String username = upToken.getUsername();

    //    if(!"wang".equals(username)) {

    //    throw new UnknownAccountException(); //如果用户名错误

    //}

    String password = String.valueOf(upToken.getPassword());

    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password .toCharArray(),getName());

    return info;

    }

    }

    4.Shiro的核心部分是SecurityManager,它负责安全认证与授权。Shiro本身已经实现了所有的细节,用户可以完全把它当做一个黑盒来使用。SecurityUtils对象,本质上就是一个工厂类似Spring中的ApplicationContext。Subject是初学者比较难于理解的对象,很多人以为它可以等同于User,其实不然。Subject中文翻译:项目,而正确的理解也恰恰如此。它是你目前所设计的需要通过Shiro保护的项目的一个抽象概念。通过令牌(token)与项目(subject)的登陆(login)关系,Shiro保证了项目整体的安全。

    新建spring-shiro.xml文件,具体内容如下:<?xml  version="1.0" encoding="UTF-8"?>

    xmlns:util="http://www.springframework.org/schema/util"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="

    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    /login = authc

    /logout = logout

    5.在spring相关的配置文件中,增加配置信息如下:

    6.修改web.xml文件增加Shiro Filter过滤器配置,具体内容如下:

    shiroFilter

    org.springframework.web.filter.DelegatingFilterProxy

    shiroFilter

    /*

    REQUEST

    展开全文
  • 最近在做hmmm项目,其中有一节讲的是自定义权限控制实现,感觉很有收获,决定将整个实现的思想和流程记录下来。 1.问题描述与分析 1.1 问题描述 系统要求不同的用户针对不同的菜单及操作应该有不同的权限。比如...

    0. 前言

    最近在做hmmm项目,其中有一节讲的是自定义权限控制的实现,感觉很有收获,决定将整个实现的思想和流程记录下来。

    1.问题描述与分析

    1.1 问题描述

    系统要求不同的用户针对不同的菜单及操作应该有不同的权限。比如管理员可以操作精选题库列表及相应的审核操作,如果是普通录入人员,只能操作基础题目菜单及题库录入的接口。所以精选题库及题目审核必须具有该权限的用户才可以操作,如果登录用户没有这个权限,系统应提示用户进行登录。

    1.2 问题分析

    权限具体是什么?权限在系统中就是一个字符串标识,标识系统的每个功能动作,比如题目新增(QUESTION_ADD)、题目删除、题目修改、题目列表获取(QUESTION_LIST),题目审核等。
    每个用户的权限,是通过角色来汇集,一个角色可以包含多个权限,一个用户可以有多个角色,比如定义了管理员角色(ROLE_ADMIN)或题目录入角色(ROLE_QUESTION_RECORDER)。这套基于权限角色的控制系统,实际是权限控制模型RBAC模型。
    (RBAC模型请参考:https://zhuanlan.zhihu.com/p/93545578
    实现最终的权限控制,需要有一套表结构支撑,最基本的表包含用户表t_user、权限表t_permission、角色表t_role、用户角色关系表t_user_role、角色权限关系表t_role_permission五张表。有的系统还需要菜单及菜单关系表,当前系统的菜单相对稳定,故暂时不需要动态实现。表格之间的关系如下图所示。简而言之,每个用户都有若干个角色,每个角色都有若干权限。
    在这里插入图片描述
    已知每个用户都有若干个角色,每个角色都有若干权限。所以有两种实现思想:

    • 一是角色匹配,每个访问路径都有允许访问的角色,当用户要访问该路径时,获取用户角色并与允许访问的角色进行匹配,若匹配成功则允许访问;
    • 二是权限匹配,用户在客户端点击某个按钮或者输入某个路径实际上是向客户端某个方法提交请求,所以,每个客户端方法应该有允许访问的权限,比如说想要审核试题就必须就有QUESTION_REVIEW_UPDATE权限,而每个用户都有自己的权限,只要进行权限匹配就可以了。

    这两种思想都是匹配的思想,具体实现方式也有两种

    • 方式一:文件配置。一般采用xml配置文件,比如下面的代码,实现的是角色匹配的思想,代码自定义了security标签,pattern代表请求路径,has_role代表允许访问该路径的角色名称。在用户登录成功后获取用户的角色,然后与访问路径对应的角色匹配,若匹配成功则允许访问。
    <security pattern="/pages/questionBasicList.html"
    has_role="ROLE_ADMIN,ROLE_QUESTION_RECORDER"/>
    <security pattern="/pages/questionClassicList.html"
    has_role="ROLE_ADMIN"/>
    
    • 方式二:注解配置。以思想二权限匹配为例,注解配置主要是通过自定义注解来配置类中哪些方法需要哪些权限或哪些角色来访问,比如下面代码,自定义了注解@HmAuthority,注解内容是QUESTION_LIST代表要想访问/question/findClassicListByPage路径必须有的权限。
    @HmAuthority("QUESTION_LIST")
    @HmRequestMapping("/question/findClassicListByPage")
    public void questionClassicList (HttpServletRequest
    request,HttpServletResponse response) throws ServletException,
    IOException {
    log.debug("questionList pageBean:{}",pageBean);
    }
    

    3. 基于xml配置文件实现权限控制

    先写一下基于xml配置文件和角色匹配实现权限控制,整体的思路和流程为:

    1. 在过滤器初始化中解析角色配置的xml文档,将访问路径与对应角色放入权限资源容器中;
    2. 获取登录用户的角色列表,判断允许访问的角色是否在用户的角色列表中,若在则允许访问,否则不允许访问。
      下面分两步实现。

    3.1 配置并在解析xml文档

    在上篇博客中讲了如何利用dom4j解析xml文档,这里再重复写一遍。

    • 首先是xml文档的配置,mm-security.xml如下所示,因为是基于maven框架,所以要吧xml文档放在resourse目录下。下述代码中pattern表示访问路径,has_role表示允许访问该路径的用户角色。
    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
    <!--授权列表-->
    <security pattern="/pages/index.html"
              has_role="ROLE_ADMIN,ROLE_QUESTION_RECORDER"/>
    <security pattern="/pages/questionBasicList.html"
              has_role="ROLE_ADMIN,ROLE_QUESTION_RECORDER"/>
    <!--<security pattern="/pages/questionClassicList.html" has_role="ROLE_ADMIN"/>-->
    <security pattern="/pages/userList.html" has_role="ROLE_ADMIN"/>
    </beans>
    
    • 过滤器的配置。必须配置过滤器才能读取到security.xml。过滤器在web.xml中配置,具体如下所示,其中<init-param>中配置的是需要解析的名字及地址。
    <!--权限过滤器-->
    <web-app>
        <filter>
            <filter-name>SecurityFilter</filter-name>
            <filter-class>com.itheima.mm.security.HmSecurityFilter</filter-class>
            <init-param>
                <param-name>SecurityConfigLocation</param-name>
                <param-value>/mm-security.xml</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>SecurityFilter</filter-name>
            <url-pattern>/*</url-pattern>   <!--对所有资源做过滤-->
        </filter-mapping>
    </web-app>
    
    • 过滤器解析xml。首先利用方法filterConfig.getInitParameter读取过滤器的初始参数,即xml的地址,将地址传入解析方法。解析方法每个步骤含义见注释,最后要把解析的资源与权限关系存入容器中。
    
    @Slf4j
    public class HmSecurityFilter implements Filter {
    	// 资源与权限容器
        private Map<String,String> authMap = new HashMap<>();
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // 初始化配置
            log.debug("HmSecurityFilter init...");
            // 读取过滤器初始化参数
            String filePath = filterConfig.getInitParameter(HmSecurityConst.CONFIG_SECURITYCONFIGLOCATION);
            // 初始化工作,解析xml,提取资源映射关系
            parseSecurityXML(filePath);
            //log
            log.debug("存储所有资源权限的authMap:{}",authMap);
        }
    
    
        // 解析xml文件
        private void parseSecurityXML(String filePath){
            log.debug("HmSecurityFilter init...解析XML...");
            // xml解析
            try{
                // 加载XML文件输入流
                InputStream resourceAsStream = this.getClass().getResourceAsStream(filePath);// 必须是
                // 构建document对象
                SAXReader saxReader = new SAXReader();
                Document document = saxReader.read(resourceAsStream);
                // 利用XPath表达式搜索Node,通过Node获取元素Element
                // 获取页面中所有的Security节点
                // "//"表示选择后代元素,即不管层次结构
                List<Node> listNodes = document.selectNodes("//"+ HmSecurityConst.TAG_SECURITY);
                // 遍历节点
                for(Node node : listNodes){
                    Element element = (Element) node;
                    // 获取元素的属性和值
                    String accessRole = element.attribute(HmSecurityConst.TAG_SECURITY_ATTR_HAS_ROLE).getStringValue();
                    String accessPath = element.attribute(HmSecurityConst.TAG_SECURITY_ATTR_PATTERN).getStringValue();
                    log.debug("获取的资源与权限关系为:");
                    log.debug("accessPath:{}",accessPath);
                    log.debug("accessRole:{}",accessRole);
                    // 把资源与权限关系存入容器
                    authMap.put(accessPath,accessRole);
                }
     
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    
    

    启动Tomcat,解析后的xml如下图所示,这也是资源与权限容器authMap中的内容。
    在这里插入图片描述

    3.2 角色匹配

    • doFilter中获取用户角色以及角色匹配。先获取用户实际请求路径,判断该路径是否在权限容器authMap中,如果没有代表该地址不需要任何权限,直接放行。如果在权限容器中,就需要获取用户的角色信息,获取用户的角色信息时要判断用户是否登录(注意:登录后创建会话,并把用户作为对象存入session中)。取出资源与权限容器authMap中的角色存入列表accessAuthArrays中,然后遍历列表,判断用户是否包含该角色,如果有,放行,否则拦截。
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            // 过滤
            log.debug("HmSecurityFilter doFilter...");
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            // 获取访问路径
            String reqPath = request.getServletPath();
            // 去点访问路径的.do
            if (reqPath.endsWith(".do")){
                reqPath = reqPath.replaceAll(".do","");
            }
            log.debug("reqPath:{}",reqPath);
            // 授权认证流程
            // 判断当前访问资源是都在权限资源容器中
            String accessAuth = authMap.get(reqPath);
            if (accessAuth == null){
                // 不在权限资源容器中,允许访问,通过
                // 允许通过,继续执行
                log.debug("不在权限资源容器中,允许访问,通过");
                chain.doFilter(request,response);
                return;
            }
            log.debug("当前访问资源路径为:{},需要的权限为:{}",reqPath,accessAuth);
    
            // 如果在容器中,需要判断当前用户的权限与资源权限是否匹配
            // 先判断用户是否登录
            HttpSession session = request.getSession(false);
            if (session == null){
                // 会话以及失效或者未登录,需要重定向到登录页面
                log.debug("会话以及失效或者未登录,需要重定向到登录页面");
                response.sendRedirect("http://localhost:8080/mm/login.html");
                return;
            }
            // session存在,获取session中的用户对象
            // 登录时将用户作为对象存入session中,key为SESSION_KEY_USER
            User user = (User) session.getAttribute(SESSION_KEY_USER);
    
            // 获取当前用户的权限列表并与资源匹配
            log.debug("获取当前用户的权限列表并与资源匹配");
            final List<String> authList = user.getAuthorityList();
            log.debug("当前用户权限列表:{}",authList);
            log.debug("当前访问的资源路径为:{},需要的权限/允许访问的角色列表为:{}",reqPath,accessAuth);
            String [] accessAuthArrays = accessAuth.split(",");
            boolean isAuthored = false;
            // 遍历资源的权限列表,每个与用户权限进行匹配
            for (String temAuth:accessAuthArrays){
                // 判断当前用户是否包含该权限,注这里判断的是当前用户的角色是否与被授权的角色匹配成功
                if (authList.contains(temAuth)){
                    isAuthored = true;
                    break;
                }
            }
            if (isAuthored){
                // 放行
                log.debug("当前用户权限与访问的资源权限匹配成功,放行!");
                chain.doFilter(request,response);
            }else {
                response.getWriter().write("权限不足,请切换用户!!");
            }
    
        }
    
    

    4. 基于注解实现权限控制

    写一下基于注解配置权限匹配实现权限控制,整体的思路和流程为:

    1. 根据1.2问题中描述,将需要进行权限控制的方法加上注解,例如@Hmthority("QUESTION_REVIEW_UPDATE"),表示访问该方法需要注解中的权限,注意:方法本身还有注解,例如@HmRequestMapping("/review/add"),表示客户端发送axios请求axios.post(app_path+"/review/add.do",params)时会直接提交到该方法(至于如何实现的这个一一对应关系的,其思想请参考我的这篇博客);
    2. 每个方法就有两个注解,将HmRequestMapping注解的内容作为key,将Hmthority注解的内容作为value放入权限容器authMap中;
    3. 用于3中类似的方法,获取登录用户的权限列表,判断当前用户是否拥有访问权限,若拥有则允许调用该方法。
    • 注: 这里也要配置一下xml文件,配置的时带注解的包所在文件夹,例如,在mm-security.xml中配置如下内容,这表示所有带有注解的方法都在mm.controller这个文件夹下。
    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
    <!--注解扫描包-->
    <scan package="mm.controller" />
    </beans>
    

    4.1 解析xml文件,获取注解方法所在文件夹

    • 过滤器init代码如下:
    @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // 初始化配置
            log.debug("HmSecurityFilter init...");
            // 读取过滤器初始化参数
            String filePath = filterConfig.getInitParameter(HmSecurityConst.CONFIG_SECURITYCONFIGLOCATION);
            // 初始化工作,解析xml,提取资源映射关系
            parseSecurityXML(filePath);
            // 解析注解
            parseAnno();
            //log
            log.debug("存储所有资源权限的authMap:{}",authMap);
        }
    
    • 解析xml方法代码如下所示:
    	private String basePackage;
    // 解析xml文件
        private void parseSecurityXML(String filePath){
            log.debug("HmSecurityFilter init...解析XML...");
            // xml解析
            try{    
           		 // 加载XML文件输入流
                InputStream resourceAsStream = this.getClass().getResourceAsStream(filePath);// 必须是
                // 构建document对象
                SAXReader saxReader = new SAXReader();
                Document document = saxReader.read(resourceAsStream);
                // 利用XPath表达式搜索Node,通过Node获取元素Element
                // 获取页面中所有的Security节点
                // "//"表示选择后代元素,即不管层次结构
                // 解析注解存在的包名
                // 解析标签对象:scan
                Node node = document.selectSingleNode("//" + HmSecurityConst.TAG_SCAN);
                Element element = (Element) node;
                // 读取包名,即读取标签对象的属性:package
                basePackage = element.attribute(HmSecurityConst.TAG_SCAN__PACKAGE).getValue();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    

    4.3 注解解析

    • 注解解析方法如下所示,每一个步骤都有详细注释;
     // 解析自定义注解
        private void parseAnno(){
            log.debug("HmSecurityFilter  init过程中解析注解,注解所在包名:{}",basePackage);
    
            // 利用工具类扫描包
            List<Class<?>> classsFromPackage = HmClassScanner.getClasssFromPackage(basePackage);
    
            // 遍历类
            for (Class clazz:classsFromPackage){
                // 判断类是否使用了HmComponent注解
                if (clazz.isAnnotationPresent(HmComponent.class)){
                    // 获取类中所有的方法
                    Method[] methods = clazz.getMethods();
                    // 遍历方法,寻找注解
                    for (Method method:methods){
                        // 寻找注解
                        if (method.isAnnotationPresent(Hmthority.class)){
                            // 获取注解中的权限值,这是访问该地址所需要的权限
                            String accessAuth = method.getAnnotation(Hmthority.class).value();
                            // 这是要访问的路径
                            String accessPath = method.getAnnotation(HmRequestMapping.class).value();
                            // 放入权限容器
                            authMap.put(accessPath,accessAuth);
    
                        }
    
                    }
    
                }
    
            }
        }
    

    启动Tomcat,解析后的资源与权限容器authMap中的内容如下图所示。
    在这里插入图片描述
    这里就表示我一共给两个方法添加了@Hmthority注解。

    4.4 权限匹配

    • 过滤器的doFilter方法代码与3.4中一致,如下所示,要注意的是3.4和4.4都是用方法user.getAuthorityList()获取角色列表或者权限列表,这一步骤要放在UserControl中设置,user是一个pojo类,里面有变量private List<String> authorityList;,需要自行编写service和dao层代码获取当前用户的权限列表或角色列表。
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            // 过滤
            log.debug("HmSecurityFilter doFilter...");
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            String reqPath = request.getServletPath();
            String contextPath = request.getContextPath();
            if (reqPath.endsWith(".do")){
                reqPath = reqPath.replaceAll(".do","");
            }
            log.debug("reqPath:{}",reqPath);
            log.debug("contextPath:{}",contextPath);
    
            // 授权认证流程
            // 判断当前访问资源是都在权限资源容器中
            String accessAuth = authMap.get(reqPath);
            if (accessAuth == null){
                // 不在权限资源容器中,允许访问,通过
                // 允许通过,继续执行
                log.debug("不在权限资源容器中,允许访问,通过");
                chain.doFilter(request,response);
                return;
            }
            log.debug("当前访问资源路径为:{},需要的权限为:{}",reqPath,accessAuth);
    
            // 如果在容器中,需要判断当前用户的权限与资源权限是否匹配
            // 先判断用户是否登录
            HttpSession session = request.getSession(false);
            if (session == null){
                // 会话以及失效或者未登录,需要重定向到登录页面
                log.debug("会话以及失效或者未登录,需要重定向到登录页面");
                response.sendRedirect("http://localhost:8080/mm/login.html");
                return;
            }
            // session存在,获取session中的用户对象
            User user = (User) session.getAttribute(SESSION_KEY_USER);
    
            // 获取当前用户的权限列表并与资源匹配
            log.debug("获取当前用户的权限列表并与资源匹配");
            final List<String> authList = user.getAuthorityList();
            log.debug("当前用户权限列表:{}",authList);
            log.debug("当前访问的资源路径为:{},需要的权限/允许访问的角色列表为:{}",reqPath,accessAuth);
            String [] accessAuthArrays = accessAuth.split(",");
            boolean isAuthored = false;
            // 遍历资源的权限列表,每个与用户权限进行匹配
            for (String temAuth:accessAuthArrays){
                // 判断当前用户是否包含该权限,注这里判断的是当前用户的角色是否与被授权的角色匹配成功
                if (authList.contains(temAuth)){
                    isAuthored = true;
                    break;
                }
            }
            if (isAuthored){
                // 放行
                log.debug("当前用户权限与访问的资源权限匹配成功,放行!");
                chain.doFilter(request,response);
            }else {
                response.getWriter().write("权限不足,请切换用户!!");
            }
        }
    
    展开全文
  • 这是最常见的,也是Java最早提供的注解。常用的有@see @param @return 等;2、跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种...
  • 学jsp这么长时间,做的项目也有七八个了,可所有的项目都是用户...在jsp中权限控制是通过Filter过滤器来实现的,所有的开发框架中都集成有Filter,如果不适用开发框架则有如下实现方法:LoginFilter.javapublic c...
  • 通过Security实现前后端分离的登录权限控制一、引入Security配置文件org.springframework.bootspring-boot-starter-security二、新建SecurityConfiguration配置类import org.springframework.beans.factory....
  • 项目使用springboot+jwt实现权限控制,在此记录一下防止以后忘记。 一、准备LoginUser 和JwtUser LoginUser.java public class LoginUser { private Integer userId; private String username; private String ...
  • } /** * 加载shiroFilter权限控制规则(从数据库读取然后配置),角色/权限信息由MyShiroCasRealm对象提供doGetAuthorizationInfo实现获取来的 * * @author SHANHY * @create 2016年1月14日 */ private void ...
  • 登录权限控制2.1.基本功能2.2.登录和未登录导航栏显示2.3.根据权限显示不同页面功能3.定制登录页和记住我功能3.1.定制登录页3.1.记住我 1.Spring Security简介 Spring Security是一个功能强大且高度可定制的身份验证...
  • 本文介绍了Spring Boot 通过AOP和自定义注解实现权限控制,分享给大家,具体如下:源码:https://github.com/yulc-coding/java-note/tree/master/aop思路自定义权限注解在需要验证的接口上加上注解,并设置具体权限...
  • 需要实现的功能:判断用户是否已登录,未登录用户禁止访问任何页面或action,自动跳转到登录页面。过程:因为对过滤器和拦截器都不熟悉,开始两种方式都问题不断,后调试通过,贴在这里留作小结和备忘过滤器filter...
  • Java注解实现权限管理

    2020-07-02 22:21:09
    一个简单的权限控制场景,已知登录用户id,判断这个用户是否存在数据库中,如果不存在则不允许进行任何操作。 关于java注解介绍请参见 Java自定义注解实现权限管理 基础实现 在每个controller方法中添加用户校验代码...
  • Java实现权限管理

    千次阅读 2017-12-12 18:09:04
    1、RBAC:基于角色的访问控制有4个元素:用户、角色、菜单、授权 权限与角色关联 ...这样不同权限的用户登录后可以看到不同的操作界面(角色与权限关联后,还要让权限与菜单(界面)关联)权限细分:
  • 下面通过一个简单的Demo来模拟这种用户权限控制实现流程,设定三种不同身份的用户,commen为普通用户,VIP为会员用户,还有一种admin为管理员。先看一下Demo的整体结构:首先搭建struts2框架的开发环境(前面博客.....
  • 在分布式的环境下,如何实现用户的单点登录以及权限控制? (1)可以使用开源软件CAS, CAS的客户端支持java,/net,php等语言 CAS的server支持多种登录方式,用户名,密码,图形。以及手机号和验证码,微信...
  • 引言: 本文系《认证鉴权与API权限控制在微服务架构中的设计与实现》系列的第一篇,本系列预计四篇文章讲解微服务下的认证鉴权与API权限控制实现。1. 背景最近在做权限相关服务的开发,在系统微服务化后,原有的...
  • Spring 整合 Shiro 实现登录认证和权限控制  JAVA herman 1年前 (2017-02-21) 4722浏览 0评论   前面有一篇文章写到了 Shiro 认证的相关数据库设计《开源权限框架 Shiro 整合 web 项目的数据库设计》。...
  • 项目描述本项目中运用了spring+springmvc+...不同的用户有不同的角色,不同的角色有不同的权限登录时间超过30分钟,系统将会自动跳转到登录页面,同时在线人数为1人,多余的人将会被踢出。运行环境jdk8+tomcat8...
  • 1、服务器端的权限判断当用户访问某个需要管理员权限才能访问的Servlet时,进行如下判断:HttpSession session = req.getSession();//判断用户的登录状态if(null == session.getAttribute("user")){//用户未登录resp...
  • 权限控制系统即用户登录后,如果操作了不能访问的操作,系统将其拦截。权限控制系统设计需求: 系统功能并不是所有功能都需要被控制,例如登录功能无需校验设计方案:资源中没有出现的功能将不被过滤 系统功能中...
  • 这种需求的系统谁做过 之前 参考了 网上博客的 ...而且也不能解决集中权限管理的问题 我想过可能需要redis来 实现这功能 但是 总感觉 这需要单点登录 结合session共享 和shiro权限 这几个技术 最好有demo 谢谢了
  • 一个简单的权限控制场景,已知登录用户id,判断这个用户是否存在数据库中,如果不存在则不允许进行任何操作。基础实现在每个controller方法中添加用户校验代码,这种可以控制到方法级,但是每个方法都要维护这段重复...
  • 权限控制系统即用户登录后,如果操作了不能访问的操作,系统将其拦截。 权限控制系统设计需求: 系统功能并不是所有功能都需要被控制,例如登录功能无需校验 设计方案:资源中没有出现的功能将不被过滤 系统...
  • Springboot + shiro +jwt 项目 Maven依赖 Springboot采用的是2.2.0 下面是jwt 和shiro的依赖 <dependency> <...java-jwt</artifactId> <version>3.2.0</version>
  • 用户权限管理一般是对...本篇博客主要是了解Shiro的基础使用方法,在权限管理系统中集成Shiro实现登录、url和页面按钮的访问控制。 一、引入依赖 使用SpringBoot集成Shiro时,在pom.xml中可以引入shiro-spring-bo...
  • 网上购物对于人们并不陌生,当人们浏览...在上述需求中,对未登录用户的权限控制就可以通过拦截器实现。下面编写案例模拟购物网站流程,要求使用 Struts2 的拦截器实现对用户的权限控制。1. 创建项目在 MyEclipse ...
  • 目前项目使用的是Struts2+Hibernate+Spring的架构模式,目前已经有一套针对SSH2的权限系统,运行良好。...权限控制分为页面和后台两块:不同类型用户的帐号分配的访问权限是不同的,用户使用帐号登录...
  • 部分代码采用mybatisCodeHelper生成,权限控制可以做到菜单和按钮级别,用户可选择记住我自动登录,缓存采用ehcache实现优化内容:优化了项目不在ROOT根目录启动时出现页面无法显示或显示不全的bug项目导入前请在id...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 488
精华内容 195
关键字:

java实现登录权限控制

java 订阅