shiro小结
来源:互联网 发布:瑞士胡椒盐包带淘宝 编辑:程序博客网 时间:2024/06/05 17:50
从本篇起,开始做一些日常工作小结。由于本人依旧属于刚入门级别,所以做出的一些总结难免会有一些不严谨,甚至是错误;但本人并不想误人子弟,只是想记录的轨迹,仅此而已。
使用shiro,先要导入相关jar包
shiro和spring的整合配置如下:
同时,web.xml中要添加:
<shiro:guest></shiro:guest>标签代表未登录时游客的访问,可以看到的内容。
<shiro:user> </shiro:user>标签代表登录以后可以看到的内容,<shiro:principal property="username"/>可以在登录以后显示用户名。
之后在进行登录的逻辑时:
注销:SecurityUtils.getSubject().logout();
这样在加入后台时,获取权限角色列表,用mybatis:
使用shiro,先要导入相关jar包
使用IDEA的,且创建的是maven工程的,可直接在pom.xml引入
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.2.2.RELEASE</version> </dependency>
shiro和spring的整合配置如下:
<?xml version="1.0" encoding="UTF-8"?><!--suppress ALL, SpringModelInspection --><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" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 配置SecurityManager、自定义Realm、定义加密算法、自定义二级缓存 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myRealm"/> <property name="rememberMeManager" ref="rememberMeManager"/> </bean> <!-- 配置自定义第三方缓存EhCache --> <bean id="shiroCache" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/> </bean> <!-- 自定义的realm --> <bean id="myRealm" class="com.jz.xd.service.shiro.MyRealm"> <!-- 添加自定义检验规则 --> <property name="credentialsMatcher" ref="passwordMatcher"/> </bean> <!-- remenberMe配置 --> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"/> <property name="httpOnly" value="true"/> <!-- 默认记住7天(单位:秒) --> <property name="maxAge" value="604800"/> </bean> <!-- rememberMe管理器 --> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/> <property name="cookie" ref="rememberMeCookie"/> </bean> <!-- 自定义加密算法 --> <bean id="passwordMatcher" class="com.jz.xd.service.shiro.CustomCredentialsMatcher"/> <!-- 过滤URL,filter。这个id名称必须和web.xml中声明的filter一致 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!--登录失败之后指向的url--> <property name="loginUrl" value="/index/toLogin"/> <!--无权限指向的页面--> <property name="unauthorizedUrl" value="/index/toLogin"/> <property name="filterChainDefinitions"> <!-- 哪些jsp,action等其他资源可以放行,哪些jsp,action不能放行。配置时按先后顺序进行url过滤 --> <value> <!--权限规则--> <!--anon:例子/admins/**=anon 没有参数,表示可以匿名使用。--> <!--authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数--> <!--roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。--> <!--perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。--> <!--rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。--> <!--port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。--> <!--authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证--> <!--ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https--> <!--user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查--> <!--静态资源和登录页不拦截--> /index.jsp =anon /html/**=anon /resources/** =anon <!--对每个Controller做拦截--> /index/**=anon /login/toInformation=user <!--...--> /login/toShopCar=authc <!--...--> /root/upload/toUploadVideo=authc,perms[/root/upload/toUploadVideo] <!--...--> </value> </property> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 生成代理,通过代理进行控制 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> <!-- 安全管理器 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean></beans>
后一个/root/upload/toUploadVideo是权限名称,可以自己重命名,这里直接用拦截的路径。
其中:
package com.jz.xd.service.shiro;import com.jz.xd.model.SPermission;import com.jz.xd.model.Srole;import com.jz.xd.model.User;import com.jz.xd.service.IndexService;import com.jz.xd.service.RootService;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.util.StringUtils;import java.util.ArrayList;import java.util.List;/** * Created by HARU on 2017/3/17. */public class MyRealm extends AuthorizingRealm { @Autowired private IndexService indexService; @Autowired private RootService rootService; private static Logger logger = LogManager.getLogger(MyRealm.class); @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("权限"); User user = (User) principalCollection.getPrimaryPrincipal(); if (user != null) { User userEntity = indexService.getUser(user.getUsername()); List<String> roles = new ArrayList<String>(); List<String> permissions = new ArrayList<String>(); List<Srole> role = rootService.getRole(userEntity); for (Srole srole : role) { roles.add(srole.getRolename()); List<SPermission> perms = indexService.getPerms(srole); for (SPermission sPermission : perms) { if (!StringUtils.isEmpty(sPermission.getUrl())) { permissions.add(sPermission.getUrl()); } } } SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //添加角色信息 simpleAuthorizationInfo.addRoles(roles); //添加权限信息 simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; } else { return null; } } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { logger.debug("验证登录"); UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken; //获取前台传入的username String username = usernamePasswordToken.getUsername(); if (!StringUtils.isEmpty(username)) { //如果用名不为空 User userEntity = indexService.getUser(username); if (userEntity == null) { userEntity = indexService.getUserByPhone(username).get(0); } if (userEntity != null) { return new SimpleAuthenticationInfo(userEntity, userEntity.getPassword(), this.getName()); } } return null; }}
package com.jz.xd.service.shiro;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;/** * Created by HARU on 2017/3/17. */public class CustomCredentialsMatcher extends SimpleCredentialsMatcher { @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { UsernamePasswordToken usertoken = (UsernamePasswordToken) token; //注意token.getPassword()拿到的是一个char[],不能直接用toString(),它底层实现不是我们想的直接字符串,只能强转 Object tokenCredentials = Encrypt.md5hash(String.valueOf(usertoken.getPassword()), Encrypt.SALT); Object accountCredentials = getCredentials(info); //将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false return equals(tokenCredentials, accountCredentials); }}
package com.jz.xd.service.shiro;import org.apache.shiro.crypto.hash.Md5Hash;/** * Created by HARU on 2017/3/17. */public class Encrypt { public static final String SALT = "HARU"; /* * 两个参数:1)需要加密密码,2)盐(混淆、动态值) 用户名 3)hash次数 * * 例如: * password=123456+“123”、“abc” */ public static String md5hash(String password, String salt) { return new Md5Hash(password, salt, 2).toString(); } public static void main(String[] args) { System.out.println(Encrypt.md5hash("root", SALT)); }}
同时,web.xml中要添加:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-service.xml,classpath:spring-shiro.xml</param-value></context-param><!--shiro 权限--><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>
<shiro:guest></shiro:guest>标签代表未登录时游客的访问,可以看到的内容。
<shiro:user> </shiro:user>标签代表登录以后可以看到的内容,<shiro:principal property="username"/>可以在登录以后显示用户名。
之后在进行登录的逻辑时:
Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); if (rememberMe == null) { rememberMe = false; } usernamePasswordToken.setRememberMe(rememberMe); subject.login(usernamePasswordToken); Object object = subject.getPrincipal(); //把信息放在Shiro的session中 //shiro默认的session就是httpSession subject.getSession().setAttribute("user", users.get(0));
注销:SecurityUtils.getSubject().logout();
补充:关于权限角色。
可以先创建几张表:
CREATE TABLE `role_perm` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色权限ID', `roleId` int(11) DEFAULT NULL COMMENT '角色ID', `permId` int(11) DEFAULT NULL COMMENT '权限ID', PRIMARY KEY (`id`))CREATE TABLE `sys_role` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID', `roleName` varchar(255) DEFAULT NULL COMMENT '角色名', `roleDescription` varchar(255) DEFAULT NULL COMMENT '角色描述', PRIMARY KEY (`id`))CREATE TABLE `sys_permission` ( `prid` int(11) NOT NULL AUTO_INCREMENT COMMENT '权限ID', `modelName` varchar(255) DEFAULT NULL COMMENT '拦截名称', `url` varchar(255) DEFAULT NULL COMMENT '拦截的路径', `parentId` int(11) DEFAULT NULL COMMENT '父Id', PRIMARY KEY (`prid`))CREATE TABLE `user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户权限ID', `uid` int(11) DEFAULT NULL COMMENT '用户iD', `roleId` int(11) DEFAULT NULL COMMENT '角色ID', PRIMARY KEY (`id`))
shiro角色权限的一个应用是在后台管理系统中,侧边栏的操作列表:
可以将一级列表设为父权限,同时也是角色名,这样表的数据如下:
权限表:
角色表(图1):
并且创建两个实体:
public class Pmenu { private String pid; private String pMenuName; private String url; private List<Cmenu> cmenus; public String getPid() { return pid; } public void setPid(String pid) { this.pid = pid; } public String getpMenuName() { return pMenuName; } public void setpMenuName(String pMenuName) { this.pMenuName = pMenuName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public List<Cmenu> getCmenus() { return cmenus; } public void setCmenus(List<Cmenu> cmenus) { this.cmenus = cmenus; }}
package com.jz.xd.model;/** * Created by HARU on 2017/6/16. */public class Cmenu { private String cid; private String cMenuName; private String url; public String getCid() { return cid; } public void setCid(String cid) { this.cid = cid; } public String getcMenuName() { return cMenuName; } public void setcMenuName(String cMenuName) { this.cMenuName = cMenuName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; }}
这样在加入后台时,获取权限角色列表,用mybatis:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.jz.xd.mapper.ext.PermissionMapperExt"> <!--id用于合并结果相关的记录--> <resultMap id="mune" type="com.jz.xd.model.Pmenu"> <id property="pid" column="pid"/> <result property="pMenuName" column="pname"/> <result property="url" column="purl"/> <collection property="cmenus" ofType="com.jz.xd.model.Cmenu"> <id property="cid" column="cid"/> <result property="cMenuName" column="cname"/> <result property="url" column="curl"/> </collection> </resultMap> <select id="getMenu" resultMap="mune"> SELECT sp_a.prid cid, sp_a.modelName cname, sp_a.url curl, sp_b.modelName pname, sp_b.prid pid, sp_b.url purl FROM roleperm srp LEFT JOIN s_permission sp_a ON srp.permId = sp_a.prid LEFT JOIN s_permission sp_b ON sp_b.prid = sp_a.parentId WHERE <if test="rIds!=null"> srp.roleId IN ( <foreach collection="rIds" index="index" item="rId" separator=","> #{rId} </foreach> ) </if> /*使用order by field(roleId,5,1)会将IN中的条件按这样的顺序查询,否则默认是按roleId递增查询*/ </select></mapper>
注意,使用这样就能体现resultMap的好处,设置了ID就可以保证,角色的唯一,即使在添加角色时,就如图1 ,添加了id为1,5的角色,即使名字都是上传,但是,进过连接,得到的权限名都会映射到同一个父权限名“上传”,且pid是相同的,所有也只会在列表上显示一个“上传”;且子权限也会同上一样,结果合并且只显示一个。
阅读全文
0 0
- shiro小结
- shiro小结
- shiro讲解 之 Authentication-Authorization小结
- shiro与web或与spring集成小结
- shiro
- shiro
- Shiro
- shiro
- shiro
- shiro
- shiro
- Shiro
- Shiro
- shiro
- shiro
- shiro
- shiro
- shiro
- 云片网短信的接入
- 基于FPGA和USB的高速数据采集及显示系统
- iOS 11 拖拽支持(drag-drop)
- System类中的arraycopy方法
- 20170611-leetcode-041-First Missing Positive
- shiro小结
- java获取客服端信息(系统,浏览器等)
- 浏览器历史记录
- 微信公众平台开发(71)OAuth2.0网页授权---流程
- 全选反选全不选
- 【js】小数精度(去位取整和四舍五入)
- TGT + TAPE
- socket.io 中文文档
- 【Java基础 三】---面向对象思想(高级)