[Shiro] - shiro之SSM中的使用
在学习shiro的途中,在github发现了一个开源项目,所需的控件刚好是自己要学习的方向.
虽然还要学习完ssm的shiro与springboot的shiro,以及接下来的种种控件和类库,但学习这个开源项目刻不容缓
[SSM的shiro使用]
SSM简单的说,就是SpringMVC负责web部分,mybatis负责数据库部分,否则没有mybatis要写的jdbc是很费时间的.
所以基于ssm的shiro项目,就是Servlet部分修改为SpringMVC,数据库部分,修改为Mybatis,然后把shiro集成进去,用这样一个思路来把项目实现.
老式Servlet:
package com.ykmimi.gobang.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class LognServlet */ @WebServlet(description = "五子棋登陆", urlPatterns = { "/login" }) public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); request.setCharacterEncoding("utf-8"); /////* 获取用户名和密码 String username = request.getParameter("username"); String password = request.getParameter("password"); PrintWriter pw = response.getWriter(); if(username.equals("admin") && password.equals("admin")) { pw.print("登陆成功!💗"); request.getRequestDispatcher("gobang.jsp"); }else { pw.print("登陆失败,请核对账户及密码.💗"); // request.getRequestDispatcher(""); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
而SpringMVC:
package com.ykmimi.controller; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import com.ykmimi.bean.User; @Controller public class UserController { @RequestMapping("login") public String login(User u,ModelMap map,HttpSession session) { System.out.println(u.getName()+":"+u.getPassword()); /*map.put("uname", u.getName()); map.put("upassword", u.getPassword());*/ session.setAttribute("User", u); return "show"; } }
可以看出Servlet的方式是通过request,response配合doGet,doPost请求进行数据的传递,而
SpringMVC是通过将一整个数据封装为bean对象,继而返回页面或者返回@ResponseBody形式(JSON).
上面将整个User用户放入了session中,这个好像不是很提倡的做法,不过这里是做个测试.
再看一眼老式的JDBC:
package com.ykmimi.ipchecker.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import com.ykmimi.ipchecker.entity.SearchingData; import com.ykmimi.ipchecker.util.JDBCUtil; public class IPAddressDao { /////* 插入新数据到表addressIp public void insertSomeData(SearchingData sdata) throws SQLException, ClassNotFoundException { Connection conn = null; PreparedStatement ps = null; String sql = "insert into addressIp values(nextval('seq_addressIp'),?,?,current_date)"; try { conn= JDBCUtil.getConnection(); ps = conn.prepareStatement(sql); ps.setString(1, sdata.getIpDomain()); ps.setString(2, sdata.getIp()); ps.executeUpdate(); }finally { JDBCUtil.close(null, ps, null); } } }
当使用之前老式的JDBC时,要分别对insert,select,update,delete等操作进行区分,牵扯到的有将不同的语句执行不同的方法.
比如select查询要执行executeQuery(),而其它的执行上面代码中的executeUpdate(),以及每个SQL语句都将写在java类中,
这与"高内聚,低耦合"的Java信条不符合,(比如SQL要进行更改时),那么就是要将SQL语句进行在解耦,Mybatis框架实现了这一操作.
Mybatis可以参考之前ukzq自己写的两篇博客 Mybatis体系结构 Mybatis基本工作原理
[代码分析]
how2j的作者偶尔也会犯错,但ssm的shiro运行还是可以的,依旧是几个页面的测试.
这里主要看一下realm包下的DatabaseRealm这个类:
package com.how2java.realm; import java.util.Set; 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.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; import org.springframework.beans.factory.annotation.Autowired; import com.how2java.service.PermissionService; import com.how2java.service.RoleService; import com.how2java.service.UserService; public class DatabaseRealm extends AuthorizingRealm { @Autowired private UserService userService; @Autowired private RoleService roleService; @Autowired private PermissionService permissionService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //能进入到这里,表示账号已经通过验证了 String userName =(String) principalCollection.getPrimaryPrincipal(); //通过service获取角色和权限 Set<String> permissions = permissionService.listPermissions(userName); Set<String> roles = roleService.listRoles(userName); //授权对象 SimpleAuthorizationInfo s = new SimpleAuthorizationInfo(); //把通过service获取到的角色和权限放进去 s.setStringPermissions(permissions); s.setRoles(roles); return s; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取账号密码 UsernamePasswordToken t = (UsernamePasswordToken) token; String userName= token.getPrincipal().toString(); String password= new String( t.getPassword()); //获取数据库中的密码 String passwordInDB = userService.getPassword(userName); //如果为空就是账号不存在,如果不相同就是密码错误,但是都抛出AuthenticationException,而不是抛出具体错误原因,免得给破解者提供帮助信息 if(null==passwordInDB || !passwordInDB.equals(password)) throw new AuthenticationException(); //认证信息里存放账号密码, getName() 是当前Realm的继承方法,通常返回当前类名 :databaseRealm SimpleAuthenticationInfo a = new SimpleAuthenticationInfo(userName,password,getName()); return a; } }
这个类继承了AuthorizingRealm,这个授权Realm,这个Realm就像how2j站长说的那样确实取的名字不够贴切,比较难以理解,说白了可能就是个用来获取用户,对比用户名以及查看其权限的一个领域.
(我更喜欢把这个Realm想象为一个大多数小区和学校,公司门口的那种栅栏,检验关口,那个地方就统称为一个域,Realm吧)
查看被继承的AuthorizingRealm,其内容大概看英文就理解为其内部实现的是一切查看验证权限,角色相关的操作,
抽空应该查看一下Shiro确切的代码解析博客.
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.apache.shiro.realm; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.Authorizer; import org.apache.shiro.authz.Permission; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.permission.PermissionResolver; import org.apache.shiro.authz.permission.PermissionResolverAware; import org.apache.shiro.authz.permission.RolePermissionResolver; import org.apache.shiro.authz.permission.RolePermissionResolverAware; import org.apache.shiro.authz.permission.WildcardPermissionResolver; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.CollectionUtils; import org.apache.shiro.util.Initializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AuthorizingRealm extends AuthenticatingRealm implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware { private static final Logger log = LoggerFactory.getLogger(AuthorizingRealm.class); private static final String DEFAULT_AUTHORIZATION_CACHE_SUFFIX = ".authorizationCache"; private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); private boolean authorizationCachingEnabled; private Cache<Object, AuthorizationInfo> authorizationCache; private String authorizationCacheName; private PermissionResolver permissionResolver; private RolePermissionResolver permissionRoleResolver; public AuthorizingRealm() { this((CacheManager)null, (CredentialsMatcher)null); } public AuthorizingRealm(CacheManager cacheManager) { this(cacheManager, (CredentialsMatcher)null); } public AuthorizingRealm(CredentialsMatcher matcher) { this((CacheManager)null, matcher); } public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) { if (cacheManager != null) { this.setCacheManager(cacheManager); } if (matcher != null) { this.setCredentialsMatcher(matcher); } this.authorizationCachingEnabled = true; this.permissionResolver = new WildcardPermissionResolver(); int instanceNumber = INSTANCE_COUNT.getAndIncrement(); this.authorizationCacheName = this.getClass().getName() + ".authorizationCache"; if (instanceNumber > 0) { this.authorizationCacheName = this.authorizationCacheName + "." + instanceNumber; } } public void setName(String name) { super.setName(name); String authzCacheName = this.authorizationCacheName; if (authzCacheName != null && authzCacheName.startsWith(this.getClass().getName())) { this.authorizationCacheName = name + ".authorizationCache"; } } public void setAuthorizationCache(Cache<Object, AuthorizationInfo> authorizationCache) { this.authorizationCache = authorizationCache; } public Cache<Object, AuthorizationInfo> getAuthorizationCache() { return this.authorizationCache; } public String getAuthorizationCacheName() { return this.authorizationCacheName; } public void setAuthorizationCacheName(String authorizationCacheName) { this.authorizationCacheName = authorizationCacheName; } public boolean isAuthorizationCachingEnabled() { return this.isCachingEnabled() && this.authorizationCachingEnabled; } public void setAuthorizationCachingEnabled(boolean authenticationCachingEnabled) { this.authorizationCachingEnabled = authenticationCachingEnabled; if (authenticationCachingEnabled) { this.setCachingEnabled(true); } } public PermissionResolver getPermissionResolver() { return this.permissionResolver; } public void setPermissionResolver(PermissionResolver permissionResolver) { if (permissionResolver == null) { throw new IllegalArgumentException("Null PermissionResolver is not allowed"); } else { this.permissionResolver = permissionResolver; } } public RolePermissionResolver getRolePermissionResolver() { return this.permissionRoleResolver; } public void setRolePermissionResolver(RolePermissionResolver permissionRoleResolver) { this.permissionRoleResolver = permissionRoleResolver; } protected void onInit() { super.onInit(); this.getAvailableAuthorizationCache(); } protected void afterCacheManagerSet() { super.afterCacheManagerSet(); this.getAvailableAuthorizationCache(); } private Cache<Object, AuthorizationInfo> getAuthorizationCacheLazy() { if (this.authorizationCache == null) { if (log.isDebugEnabled()) { log.debug("No authorizationCache instance set. Checking for a cacheManager..."); } CacheManager cacheManager = this.getCacheManager(); if (cacheManager != null) { String cacheName = this.getAuthorizationCacheName(); if (log.isDebugEnabled()) { log.debug("CacheManager [" + cacheManager + "] has been configured. Building authorization cache named [" + cacheName + "]"); } this.authorizationCache = cacheManager.getCache(cacheName); } else if (log.isDebugEnabled()) { log.debug("No cache or cacheManager properties have been set. Authorization cache cannot be obtained."); } } return this.authorizationCache; } private Cache<Object, AuthorizationInfo> getAvailableAuthorizationCache() { Cache<Object, AuthorizationInfo> cache = this.getAuthorizationCache(); if (cache == null && this.isAuthorizationCachingEnabled()) { cache = this.getAuthorizationCacheLazy(); } return cache; } protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { return null; } else { AuthorizationInfo info = null; if (log.isTraceEnabled()) { log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); } Cache<Object, AuthorizationInfo> cache = this.getAvailableAuthorizationCache(); Object key; if (cache != null) { if (log.isTraceEnabled()) { log.trace("Attempting to retrieve the AuthorizationInfo from cache."); } key = this.getAuthorizationCacheKey(principals); info = (AuthorizationInfo)cache.get(key); if (log.isTraceEnabled()) { if (info == null) { log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); } else { log.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); } } } if (info == null) { info = this.doGetAuthorizationInfo(principals); if (info != null && cache != null) { if (log.isTraceEnabled()) { log.trace("Caching authorization info for principals: [" + principals + "]."); } key = this.getAuthorizationCacheKey(principals); cache.put(key, info); } } return info; } } protected Object getAuthorizationCacheKey(PrincipalCollection principals) { return principals; } protected void clearCachedAuthorizationInfo(PrincipalCollection principals) { if (principals != null) { Cache<Object, AuthorizationInfo> cache = this.getAvailableAuthorizationCache(); if (cache != null) { Object key = this.getAuthorizationCacheKey(principals); cache.remove(key); } } } protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1); protected Collection<Permission> getPermissions(AuthorizationInfo info) { Set<Permission> permissions = new HashSet(); if (info != null) { Collection<Permission> perms = info.getObjectPermissions(); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } perms = this.resolvePermissions(info.getStringPermissions()); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } perms = this.resolveRolePermissions(info.getRoles()); if (!CollectionUtils.isEmpty(perms)) { permissions.addAll(perms); } } return permissions.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(permissions); } private Collection<Permission> resolvePermissions(Collection<String> stringPerms) { Collection<Permission> perms = Collections.emptySet(); PermissionResolver resolver = this.getPermissionResolver(); if (resolver != null && !CollectionUtils.isEmpty(stringPerms)) { perms = new LinkedHashSet(stringPerms.size()); Iterator var4 = stringPerms.iterator(); while(var4.hasNext()) { String strPermission = (String)var4.next(); Permission permission = this.getPermissionResolver().resolvePermission(strPermission); ((Collection)perms).add(permission); } } return (Collection)perms; } private Collection<Permission> resolveRolePermissions(Collection<String> roleNames) { Collection<Permission> perms = Collections.emptySet(); RolePermissionResolver resolver = this.getRolePermissionResolver(); if (resolver != null && !CollectionUtils.isEmpty(roleNames)) { perms = new LinkedHashSet(roleNames.size()); Iterator var4 = roleNames.iterator(); while(var4.hasNext()) { String roleName = (String)var4.next(); Collection<Permission> resolved = resolver.resolvePermissionsInRole(roleName); if (!CollectionUtils.isEmpty(resolved)) { ((Collection)perms).addAll(resolved); } } } return (Collection)perms; } public boolean isPermitted(PrincipalCollection principals, String permission) { Permission p = this.getPermissionResolver().resolvePermission(permission); return this.isPermitted(principals, p); } public boolean isPermitted(PrincipalCollection principals, Permission permission) { AuthorizationInfo info = this.getAuthorizationInfo(principals); return this.isPermitted(permission, info); } protected boolean isPermitted(Permission permission, AuthorizationInfo info) { Collection<Permission> perms = this.getPermissions(info); if (perms != null && !perms.isEmpty()) { Iterator var4 = perms.iterator(); while(var4.hasNext()) { Permission perm = (Permission)var4.next(); if (perm.implies(permission)) { return true; } } } return false; } public boolean[] isPermitted(PrincipalCollection subjectIdentifier, String... permissions) { List<Permission> perms = new ArrayList(permissions.length); String[] var4 = permissions; int var5 = permissions.length; for(int var6 = 0; var6 < var5; ++var6) { String permString = var4[var6]; perms.add(this.getPermissionResolver().resolvePermission(permString)); } return this.isPermitted((PrincipalCollection)subjectIdentifier, (List)perms); } public boolean[] isPermitted(PrincipalCollection principals, List<Permission> permissions) { AuthorizationInfo info = this.getAuthorizationInfo(principals); return this.isPermitted(permissions, info); } protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) { boolean[] result; if (permissions != null && !permissions.isEmpty()) { int size = permissions.size(); result = new boolean[size]; int i = 0; Permission p; for(Iterator var6 = permissions.iterator(); var6.hasNext(); result[i++] = this.isPermitted(p, info)) { p = (Permission)var6.next(); } } else { result = new boolean[0]; } return result; } public boolean isPermittedAll(PrincipalCollection subjectIdentifier, String... permissions) { if (permissions != null && permissions.length > 0) { Collection<Permission> perms = new ArrayList(permissions.length); String[] var4 = permissions; int var5 = permissions.length; for(int var6 = 0; var6 < var5; ++var6) { String permString = var4[var6]; perms.add(this.getPermissionResolver().resolvePermission(permString)); } return this.isPermittedAll((PrincipalCollection)subjectIdentifier, (Collection)perms); } else { return false; } } public boolean isPermittedAll(PrincipalCollection principal, Collection<Permission> permissions) { AuthorizationInfo info = this.getAuthorizationInfo(principal); return info != null && this.isPermittedAll(permissions, info); } protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) { if (permissions != null && !permissions.isEmpty()) { Iterator var3 = permissions.iterator(); while(var3.hasNext()) { Permission p = (Permission)var3.next(); if (!this.isPermitted(p, info)) { return false; } } } return true; } public void checkPermission(PrincipalCollection subjectIdentifier, String permission) throws AuthorizationException { Permission p = this.getPermissionResolver().resolvePermission(permission); this.checkPermission(subjectIdentifier, p); } public void checkPermission(PrincipalCollection principal, Permission permission) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkPermission(permission, info); } protected void checkPermission(Permission permission, AuthorizationInfo info) { if (!this.isPermitted(permission, info)) { String msg = "User is not permitted [" + permission + "]"; throw new UnauthorizedException(msg); } } public void checkPermissions(PrincipalCollection subjectIdentifier, String... permissions) throws AuthorizationException { if (permissions != null) { String[] var3 = permissions; int var4 = permissions.length; for(int var5 = 0; var5 < var4; ++var5) { String permString = var3[var5]; this.checkPermission(subjectIdentifier, permString); } } } public void checkPermissions(PrincipalCollection principal, Collection<Permission> permissions) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkPermissions(permissions, info); } protected void checkPermissions(Collection<Permission> permissions, AuthorizationInfo info) { if (permissions != null && !permissions.isEmpty()) { Iterator var3 = permissions.iterator(); while(var3.hasNext()) { Permission p = (Permission)var3.next(); this.checkPermission(p, info); } } } public boolean hasRole(PrincipalCollection principal, String roleIdentifier) { AuthorizationInfo info = this.getAuthorizationInfo(principal); return this.hasRole(roleIdentifier, info); } protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) { return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier); } public boolean[] hasRoles(PrincipalCollection principal, List<String> roleIdentifiers) { AuthorizationInfo info = this.getAuthorizationInfo(principal); boolean[] result = new boolean[roleIdentifiers != null ? roleIdentifiers.size() : 0]; if (info != null) { result = this.hasRoles(roleIdentifiers, info); } return result; } protected boolean[] hasRoles(List<String> roleIdentifiers, AuthorizationInfo info) { boolean[] result; if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { int size = roleIdentifiers.size(); result = new boolean[size]; int i = 0; String roleName; for(Iterator var6 = roleIdentifiers.iterator(); var6.hasNext(); result[i++] = this.hasRole(roleName, info)) { roleName = (String)var6.next(); } } else { result = new boolean[0]; } return result; } public boolean hasAllRoles(PrincipalCollection principal, Collection<String> roleIdentifiers) { AuthorizationInfo info = this.getAuthorizationInfo(principal); return info != null && this.hasAllRoles(roleIdentifiers, info); } private boolean hasAllRoles(Collection<String> roleIdentifiers, AuthorizationInfo info) { if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) { Iterator var3 = roleIdentifiers.iterator(); while(var3.hasNext()) { String roleName = (String)var3.next(); if (!this.hasRole(roleName, info)) { return false; } } } return true; } public void checkRole(PrincipalCollection principal, String role) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkRole(role, info); } protected void checkRole(String role, AuthorizationInfo info) { if (!this.hasRole(role, info)) { String msg = "User does not have role [" + role + "]"; throw new UnauthorizedException(msg); } } public void checkRoles(PrincipalCollection principal, Collection<String> roles) throws AuthorizationException { AuthorizationInfo info = this.getAuthorizationInfo(principal); this.checkRoles(roles, info); } public void checkRoles(PrincipalCollection principal, String... roles) throws AuthorizationException { this.checkRoles((PrincipalCollection)principal, (Collection)Arrays.asList(roles)); } protected void checkRoles(Collection<String> roles, AuthorizationInfo info) { if (roles != null && !roles.isEmpty()) { Iterator var3 = roles.iterator(); while(var3.hasNext()) { String roleName = (String)var3.next(); this.checkRole(roleName, info); } } } protected void doClearCache(PrincipalCollection principals) { super.doClearCache(principals); this.clearCachedAuthorizationInfo(principals); } }
在DatabaseRealm中:
@Autowired private UserService userService; @Autowired private RoleService roleService; @Autowired private PermissionService permissionService;
分别表示的是用户的service, 角色的service, 权限许可操作的service,用来执行不同的操作.
与SpringBoot不同的是SSM配置xml文件:
applicationContext-shiro.xml 把原来的shiro.ini进行了另一种写法的展示
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 调用我们配置的权限管理器 --> <property name="securityManager" ref="securityManager" /> <!-- 配置我们的登录请求地址 --> <property name="loginUrl" value="/login" /> <!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 --> <property name="unauthorizedUrl" value="/unauthorized" /> <!-- 退出 --> <property name="filters"> <util:map> <entry key="logout" value-ref="logoutFilter" /> </util:map> </property> <!-- 权限配置 --> <property name="filterChainDefinitions"> <value> <!-- anon表示此地址不需要任何权限即可访问 --> /login=anon /index=anon /static/**=anon /doLogout=logout <!--所有的请求(除去配置的静态资源请求或请求地址为anon的请求)都要通过登录验证,如果未登录则跳到/login --> /** = authc </value> </property> </bean> <!-- 退出过滤器 --> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="/index" /> </bean> <!-- 会话ID生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" /> <!-- 会话Cookie模板 关闭浏览器立即失效 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid" /> <property name="httpOnly" value="true" /> <property name="maxAge" value="-1" /> </bean> <!-- 会话DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="sessionIdGenerator" ref="sessionIdGenerator" /> </bean> <!-- 会话验证调度器,每30分钟执行一次验证 ,设定会话超时及保存 --> <bean name="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler"> <property name="interval" value="1800000" /> <property name="sessionManager" ref="sessionManager" /> </bean> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- 全局会话超时时间(单位毫秒),默认30分钟 --> <property name="globalSessionTimeout" value="1800000" /> <property name="deleteInvalidSessions" value="true" /> <property name="sessionValidationSchedulerEnabled" value="true" /> <property name="sessionValidationScheduler" ref="sessionValidationScheduler" /> <property name="sessionDAO" ref="sessionDAO" /> <property name="sessionIdCookieEnabled" value="true" /> <property name="sessionIdCookie" ref="sessionIdCookie" /> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="databaseRealm" /> <property name="sessionManager" ref="sessionManager" /> </bean> <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager" /> <property name="arguments" ref="securityManager" /> </bean> <bean id="databaseRealm" class="com.how2java.realm.DatabaseRealm"> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> </beans>
applicationContext.xml 数据库连接,扫描mybatis的mapper什么的.
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:annotation-config /> <context:component-scan base-package="com.how2java.service" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8</value> </property> <property name="username"> <value>root</value> </property> <property name="password"> <value>yourpassword</value> </property> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="typeAliasesPackage" value="com.how2java.pojo" /> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:com/how2java/mapper/*.xml"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.how2java.mapper"/> </bean> </beans>
为什么zhang3只能点击进入删除订单的权限,而li4不能.?
deleteOrder.jsp ,能进来,就表示有deleteOrder权限
返回
除了这两个xml,还有web.xml,springMVC.xml,并没有很显著地对点击路径进行Filter拦截,那样的话,如果项目比较大,拦截的页面会有很多
而且要根据不同角色,不同权限进行拦截,想起来都觉得麻烦.
这里看到PageController中,其实是使用了一个注解
package com.how2java.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; //专门用于显示页面的控制器 @Controller @RequestMapping("") public class PageController { @RequestMapping("index") public String index(){ return "index"; } @RequiresPermissions("deleteOrder") @RequestMapping("deleteOrder") public String deleteOrder(){ return "deleteOrder"; } @RequiresRoles("productManager") @RequestMapping("deleteProduct") public String deleteProduct(){ return "deleteProduct"; } @RequestMapping("listProduct") public String listProduct(){ return "listProduct"; } @RequestMapping(value="/login",method=RequestMethod.GET) public String login(){ return "login"; } @RequestMapping("unauthorized") public String noPerms(){ return "unauthorized"; } }
除了熟悉的RequestMapping,Controller, 这里多出来两个,一个叫@RequiresPermissions("deleteOrder"),字面意思理解就是要访问这个deleteOrder路径的需要一个叫deleteOrder的权限
再返回去看数据库表中permission这个表的内容:
以及role_permission
看了这两个表就应该清楚的知道,一个表定义了整个shiro加入的系统中有哪些操作.
最后,role的id, 1,2,3, 对应 role_permission表中那些操作,比如role中id为1的admin,它具有permission表中1,2,3,4,5,6,7,8,9,10的操作.
如果一个方法同时声明多个这样的注解,那么它们的判定顺序跟注解的上下顺序无关,而是根据这个:
图片引自博客 某csdn
依次看这些注解的含义:
RequiresRoles -- 当前Subject必须拥有所指定的角色时,才能访问被该注解标注的方法,如果当Subject不同时,不拥有所有指定角色,则
方法不会执行,还会抛出AuthorizationException异常.
RequiresPermissions -- 当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法,就像上面的需要deleteOrder的权限,如
果当前Subject不具有这样的权限,则方法不会被执行.
RequiresAuthentication -- 使用该注解标注的类,实例,方法在访问或调用时,当前Subject必须在当前session中已经过认证.
验证用户是否登录,等同于方法subject.isAuthenticated() 结果为true时。
RequiresUser -- 当前Subject必须是应用的用户,才能访问或调用被该注解标注的类,实例,方法.
验证用户是否被记忆,user有两种含义:
一种是成功登录的(subject.isAuthenticated() 结果为true);
另外一种是被记忆的(subject.isRemembered()结果为true).
RequiresGuest -- 使用该注解标注的类,实例,方法在访问或调用时,当前Subject可以是"guest"身份,不需要经过认证或在之前的session中存在记录.
验证是否是一个guest的请求,与@RequiresUser完全相反。换言之,RequiresUser == !RequiresGuest。此时subject.getPrincipal() 结果为null.
上面的web.xml中配置的filter是跟shiro相关的.
<!-- 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> </filter-mapping>
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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <context:annotation-config/> <context:component-scan base-package="com.how2java.controller"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <mvc:annotation-driven /> <mvc:default-servlet-handler /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!--启用shiro注解 --> <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> <!-- 控制器异常处理 --> <bean id="exceptionHandlerExceptionResolver" class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"> </bean> <bean class="com.how2java.exception.DefaultExceptionHandler"/> </beans>
刚看了看B站上面的shiro教程,讲得好细. 放在之后听.
SSM的shiro到这里其实也没什么可记录的了,注意AuthorizationInfo这个对象可以存放角色和权限信息.
其它的根据权限5表设计的bean,对应的Mapper注意角色和权限是List集合,因为一个用户可能具备多种角色,多种权限.
这里接触到一个新的注解 @ResponseStatus
今天ssm的shiro整理到这里,也基本差不多了.
本文来自博客园,作者:ukyo--君君小时候,转载请注明原文链接:https://www.cnblogs.com/ukzq/p/10227726.html