简单权限系统基于shiro-springmvc-spring-mybatis(学习笔记2)

学习笔记(1)链接:http://blog.csdn.net/qq_15370821/article/details/52798276

一个简单的权限管理系统,实现用户、权限、资源的增删改查,这三者之间相互的授权和取消授权,如:一个用户可以拥有多个权限并且一个权限可以拥有多个资源。

系统基于shiro、springmvc、spring、mybatis,使用MySQL数据库。
项目地址:https://git.oschina.net/beyondzl/spring-shiro
(前端视图由于时间原因没有全部完成,后端功能测试可行)

Web层

springmvc.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

    <mvc:annotation-driven >
        <mvc:message-converters register-defaults="false">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="utf-8"></constructor-arg>
            </bean>
            <ref bean="jacksonMessageConverter"></ref>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/html;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
        <property name="objectMapper" ref="jacksonObjectMapper"></property>
    </bean>

    <context:component-scan base-package="com.spring.shiro.main.java.controller"></context:component-scan>



    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
        <!-- 有多个视图解析器时的优先级 -->
        <property name="order" value="10"></property>
    </bean>
</beans>

基础Controller类:

public abstract class BaseController {

    @Autowired
    private UserService userService ;

    /**
     * 日期格式转换
     * @param binder
     */
    @InitBinder
    public void initBinder(ServletRequestDataBinder binder) {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));

        /**
         * 防止XSS攻击
         */
        binder.registerCustomEditor(String.class, new StringEscapeEditor(true,false));
    }

    /**
     * 获取当前登录用户
     * @return
     */
    public User getCurrentUser() {
        ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
        User currentUser = userService.findUserById(user.id);
        return currentUser;
    }

    /*
     * 获取当前用户id
     */
    public Long getUserUd() {
        return this.getCurrentUser().getId();
    }

    /**
     * 获取当前用户名
     * @return
     */
    public String getStaffName() {
        return this.getCurrentUser().getName();
    }

    /**
     * ajax失败
     * @param msg 失败的消息
     * @return
     */
    public Object renderError(String msg) {
        Result result = new Result();
        result.setMsg(msg);
        return result;

    }

    /**
     * ajax成功
     * @return
     */
    public Object renderSuccess() {
        Result result = new Result();
        result.setSuccess(true);
        return result;
    }

    /**
     * ajax成功消息
     * @param msg
     * @return
     */
    public Object renderSuccess(String msg) {
        Result result = new Result();
        result.setSuccess(true);
        result.setMsg(msg);
        return result;
    }

    /**
     * ajax成功时的对象
     * @param obj
     * @return
     */
    public Object renderSuccess(Object obj) {
        Result result = new Result();
        result.setSuccess(true);
        result.setObj(obj);
        return result;
    }
}

handler继承基本Controller类:

@Controller
@RequestMapping("/user")
public class UserController extends BaseController {
    @Autowired
    private UserService userService;

    /**
     * 用户管理页
     * @return
     */
    @RequestMapping(value="/manager",method=RequestMethod.GET)
    public String manager() {
        return "/admin/user";
    }

    /**
     * 用户管理列表
     * @param userVo
     * @param page
     * @param rows
     * @param sort
     * @return
     */
    @RequestMapping(value="/dataGrid", method=RequestMethod.POST)
    @ResponseBody
    public Object dataGrid(UserVo userVo, Integer page, Integer rows, String sort) {
        PageInfo pageInfo = new PageInfo(page, rows);
        Map<String, Object> condition = new HashMap<String, Object>();

        if(StringUtils.hasText(userVo.getName())) {
            condition.put("name", userVo.getName());
        }
        if(userVo.getOrganizationId() != null) {
            condition.put("organizationId", userVo.getOrganizationId());
        }
        if(userVo.getCreatedateStart() != null) {
            condition.put("startTime", userVo.getCreatedateStart());
        }
        if(userVo.getCreatedateEnd() != null) {
            condition.put("endTime", userVo.getCreatedateEnd());
        }
        pageInfo.setCondition(condition);
        userService.findUserGrid(pageInfo);
        return pageInfo;

    }

    /**
     * 添加用户页
     * @return
     */
    @RequestMapping(value="addPage", method=RequestMethod.GET)
    public String addPage() {
        return "/admin/userAdd";
    }

    /**
     * 添加用户
     * @param userVo
     * @return
     */
    @RequestMapping(value="/add",method=RequestMethod.POST)
    @ResponseBody
    public Object add(UserVo userVo)  {
        User user = userService.findUserByLoginName(userVo.getLoginName());
        if(user != null) {
            return renderError("用户名已存在!");
        }
        try {
            userVo.setPassword(DigestUtils.md5Hex(userVo.getPassword().getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            return renderSuccess("添加失败!");
        }
        userService.addUser(userVo);
        return renderSuccess("添加成功!");
    }

    /**
     * 编辑用户页
     * @param id
     * @param model
     * @return
     */
    @RequestMapping("/editPage")
    public String editPage(Long id,Model model) {
        UserVo userVo = userService.findUserVoById(id);
        List<Role> rolesList = userVo.getRolesList();
        List<Long> idsList = new ArrayList<Long>();
        for(Role role : rolesList) {
            idsList.add(role.getId());
        }
        model.addAttribute("roleIds", rolesList);
        model.addAttribute("user", userVo);
        return "/admin/userEdit";
    }

    @RequestMapping("/edit") 
    @ResponseBody
    public Object edit(UserVo userVo) {
        User user = userService.findUserByLoginName(userVo.getLoginName());
        if(user != null && user.getId() != userVo.getId()) {
            return renderError("用户名已存在!");
        }
        try {
            userVo.setPassword(DigestUtils.md5Hex(userVo.getPassword().getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            return renderError("添加失败!");

        }

        userService.addUser(userVo);
        return renderSuccess("添加成功!");
    }

    /**
     * 修改密码页
     * @return
     */
    @RequestMapping(value="/editPwdPage", method=RequestMethod.GET)
    public String editPwdPage() {
        return "/admin/userEditPwd";
    }

    @RequestMapping("/editUserPwd")
    @ResponseBody
    public Object editUserPwd(String oldPwd, String pwd) {
        try {
            if(!getCurrentUser().getPassword().equals(DigestUtils.md5Hex(oldPwd.getBytes("UTF-8")))) {
                return renderError("旧密码错误!");
            }
        } catch (UnsupportedEncodingException e) {
            return renderError("修改失败!");
        }
        userService.updateUserPwdById(getUserUd(), pwd);
        return renderSuccess("修改成功!");

    }

    @RequestMapping("/delete")
    @ResponseBody
    public Object delete(Long id) {
        userService.deleteUserById(id);
        return renderSuccess("删除成功!");
    }
}

spirng整合shiro

spring-shiro.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    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">

    <description>shiro安全配置</description>

    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" >
        <!-- 设置自定义realm -->
        <property name="realm" ref="shiroDbRealm"></property>
        <!-- 将缓存管理器交给安全管理器 -->
        <property name="cacheManager" ref="shiroEhcacheManager"></property>
    </bean>

    <!-- 自定义realm -->
    <bean id="shiroDbRealm" class="com.spring.shiro.main.common.shiro.ShiroDbRealm"></bean>

    <!-- shiro Filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 安全管理器 -->
        <property name="securityManager" ref="securityManager"></property>
        <!-- 默认的登陆访问url -->
        <property name="loginUrl" value="/login"></property>
        <!-- 登陆成功后跳转的url -->
        <property name="successUrl" value="/index"></property>
        <!-- 没有权限跳转的url -->
        <property name="unauthorizedUrl" value="/unauth"></property>
        <property name="filterChainDefinitions">
            <value>
                /commons/** = anon <!-- 不需要认证 -->
                /static/** = anon
                /login = anon
                /** = authc <!-- 需要认证 -->
            </value>
        </property>
    </bean>

    <!-- 用户授权信息cache 才用Ehcache -->
    <bean id="ShiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"></property>
    </bean>

    <!-- 在方法中注入securityManager进行代理控制 -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"></property>
        <property name="arguments" ref="securityManager"></property>
    </bean>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>

    <!-- AOP方法级权限检查 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"></bean>

    <!-- 启用shiro授权注解拦截方式 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"></property>
    </bean>
</beans>

ehcache配置
ehcache-shiro.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache">
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        overToLiveSeconds="120"
        overflowToDisk="false"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120" 
    />
</ehcache>

shiro权限认证类:

public class ShiroDbRealm extends AuthorizingRealm {

    private static Logger LOGGER = LogManager.getLogger(ShiroDbRealm.class);
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;

    /**
     * 权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {

        ShiroUser shiroUser = (ShiroUser)principal.getPrimaryPrincipal();
        List<Long> roleList = shiroUser.roleList;

        Set<String> urlSet = new HashSet<String>();
        for(Long roleId : roleList) {
            List<Map<Long, String>> roleResourceList = roleService.findRoleResourceListByRoleId(roleId);
            if(roleResourceList != null) {
                for(Map<Long,String> map : roleResourceList) {
                    if(StringUtils.hasText(map.get("url"))) {
                        urlSet.add(map.get("url"));
                    }
                }
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(urlSet);
        return info;
    }

    /**
     * shiro登陆认证 用户提交用户名密码,shiro封装令牌,realm通过用户名密码查询返回,shiro自动比较用户名密码是否匹配哦,进行登陆控制
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        LOGGER.info("Shiro开始登陆认证");
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        User user = userService.findUserByLoginName(token.getUsername());

        if(user == null) {
            return null;
        }
        //账号未启用
        if(user.getStatus() == 1) {
            return null;
        }

        List<Long> roleList = roleService.findRoleIdsByUserId(user.getId());
        ShiroUser shiroUser = new ShiroUser(user.getId(), user.getLoginName(), user.getName(),roleList);
        //认证缓存器
        return new SimpleAuthenticationInfo(shiroUser, user.getPassword().toCharArray(), getName());



    }

}

字符串处理工具类:

public class StringEscapeEditor extends PropertyEditorSupport{
    private boolean escaoeHTML; //编码HTML
    private boolean escapeJavaScript; //编码javascript

    public StringEscapeEditor(){}

    public StringEscapeEditor(boolean escapeHTML, boolean escapeJavaScipt){
        this.escaoeHTML = escapeHTML;
        this.escapeJavaScript = escapeJavaScipt;
    }

    @Override
    public String getAsText() {
        Object value = getValue();
        return value != null ? value.toString() : "";
    }

    @Override
    public void setAsText(String text) {
        if(text == null) {
            setValue(null);
        }
        else {
            String value = text;
            if(escaoeHTML) {
                value = HtmlUtils.htmlEscape(value);
            }
            if(escapeJavaScript) {
                value = JavaScriptUtils.javaScriptEscape(value);
            }
            setValue(value);
        }
    }
}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>spring-shiro</display-name>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <!-- springmvc控制器 -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet.class</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <!-- 是否支持异步 -->
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <filter>
    <filter-name>DruidWebStatFilter</filter-name>
    <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
    <init-param>
        <param-name>exclusions</param-name>
        <param-value>/static/*,*.js,*.gif,*.png,*.css,*.ico,/druid/*</param-value>
    </init-param>
    <init-param>
        <param-name>sessionStatEnable</param-name>
        <param-value>false</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>DruidWebStatFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- shiro过滤 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
  </filter-mapping>

  <!-- 错误页面 -->
 <error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/views/error/404.jsp</location>
 </error-page>
 <error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/error/500.jsp</location>
 </error-page>
</web-app>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值