安全框架——Shiro使用教程
发布日期:2021-05-07 08:40:57 浏览次数:13 分类:技术文章

本文共 25099 字,大约阅读时间需要 83 分钟。

文章目录

1. 下载

  • 选择Source Code Distribution,下载,解压

2. 测试

实际开发使用注解的方式,搭建web开发环境,不会在ini配置文件进行硬编码的操作

  • 测试样例参考shiro解压目录\samples\quickstart
  • 需要的jar包
shiro-all.jarlog4j.jarslf4j-api.jarslf4j-log4j12.jar
  • 官方shiro.ini文件(截取部分文件)
[users]# 用户 'root' 密码 'secret' 角色 'admin' root = secret, admin# 用户 'guest' 密码 'guest' 角色 'guest' guest = guest, guest# 用户 'darkhelmet' 密码 'ludicrousspeed' 角色 'darklord' and 'schwartz'darkhelmet = ludicrousspeed, darklord, schwartz[roles]# 'admin' role has all permissions, indicated by the wildcard '*'admin = *# The 'schwartz' role can do anything (*) with any lightsaber:schwartz = lightsaber:*# 用户名 = 类型-用户:操作-删除:实例-张三--->goodgay 可以删除张三的用户信息# 主:谓:宾goodguy = user:delete:zhangsan
  • 官方Quickstart.java:\samples\quickstart\src\main\java\Quickstart.java
public class Quickstart {       private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);    public static void main(String[] args) {       	// 使用ini配置文件配置realms, users, roles and permissions,创建Shiro SecurityManager        Factory
factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); /** * 如何操作shiro 模拟用户、密码、角色、权限都在ini配置文件里 */ // 1. 获取当前的 Subject. 调用 SecurityUtils.getSubject(); Subject currentUser = SecurityUtils.getSubject(); // 获取 Session: Subject#getSession() Session session = currentUser.getSession(); session.setAttribute("someKey", "aValue"); String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { log.info("---> Retrieved the correct value! [" + value + "]"); } // 2. 测试当前的用户是否已经被认证. 即是否已经登录. // 调动 Subject 的 isAuthenticated() if (!currentUser.isAuthenticated()) { // 把用户名和密码封装为 UsernamePasswordToken 对象 UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); // rememberme token.setRememberMe(true); try { // 执行登录. currentUser.login(token); } // 若没有指定的账户, 则 shiro 将会抛出 UnknownAccountException 异常. catch (UnknownAccountException uae) { log.info("----> There is no user with username of " + token.getPrincipal()); return; } // 若账户存在, 但密码不匹配, 则 shiro 会抛出 IncorrectCredentialsException 异常。 catch (IncorrectCredentialsException ice) { log.info("----> Password for account " + token.getPrincipal() + " was incorrect!"); return; } // 用户被锁定的异常 LockedAccountException catch (LockedAccountException lae) { log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // 所有认证时异常的父类. catch (AuthenticationException ae) { //unexpected condition? error? } } //say who they are: //print their identifying principal (in this case, a username): log.info("----> User [" + currentUser.getPrincipal() + "] logged in successfully."); // 测试是否有某一个角色. 调用 Subject 的 hasRole 方法. if (currentUser.hasRole("schwartz")) { log.info("----> May the Schwartz be with you!"); } else { log.info("----> Hello, mere mortal."); return; } // 测试用户是否具备某一个行为. 调用 Subject 的 isPermitted() 方法。 if (currentUser.isPermitted("lightsaber:weild")) { log.info("----> You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); } // 测试用户是否具备某一个行为. if (currentUser.isPermitted("user:delete:zhangsan")) { log.info("----> You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } // 执行登出. 调用 Subject 的 Logout() 方法. 通过测试用户是否被认证来查看用户是否登陆退出 System.out.println("---->" + currentUser.isAuthenticated()); currentUser.logout(); System.out.println("---->" + currentUser.isAuthenticated()); System.exit(0); }}

3. SSM整合教程

3.1 基本认证流程

  1. 获取当前的 Subject,调用 SecurityUtils.getSubject()
  2. 测试当前的用户是否已经被认证. 即是否已经登录,调用 Subject 的 isAuthenticated() 方法
  3. 如果没有被认证,则把用户名和密码(通过将表单信息提交到SpringMVC中)封装为 UsernamePasswordToken 对象
  4. 执行登录,调用 Subject 的 login(token) 方法
  5. 自定义Realm,继承 AuthenticatingRealm,实现 doGetAuthenticationInfo(),通过数据库获取对应记录,返回给shiro
  6. 通过shiro完成密码比对:前台输入的 UsernamePasswordToken 与 数据库查询的 SimpleAuthenticationInfo 信息进行比对

3.2 基本配置

  • 依赖管理:修改pom.xml
org.apache.shiro
shiro-core
1.2.4
org.apache.shiro
shiro-web
1.2.4
org.apache.shiro
shiro-spring
1.2.4
  • 修改web.xml
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
shiroFilter
/*
  • 新建spring-shiro.xml
/login.jsp = anon /shiro/login = anon /shiro/logout = logout # everything else requires authentication: /** = authc
  • 在spring.xml文件中导入spring-shiro.xml
  • 自定义Realm
public class ShiroRealm extends AuthenticatingRealm{   		/**	 * token:是SpringMVC从请求中获取的	 */	@Override	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {   		System.out.println("token.hashCode() = " + token.hashCode());		//1. 把 AuthenticationToken 转换为 UsernamePasswordToken 		UsernamePasswordToken upToken = (UsernamePasswordToken) token;				//2. 从 UsernamePasswordToken 中来获取 username		String username = upToken.getUsername();				//3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录		System.out.println("用户名:"+username);				//4. 若用户不存在, 则可以抛出 UnknownAccountException 异常		if("unknown".equals(username)){   			throw new UnknownAccountException("用户不存在!");		}				//5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常 		if("locked".equals(username)){   			throw new LockedAccountException("用户被锁定!");		}				//6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo		//1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象		Object principal = username;		//2). credentials: 从数据库中获取密码,以下是在本地模拟		Object credentials = "123456"; 		//3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可		String realmName = getName();				SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);		return info;	}}
  • login.jsp
username:
password:
  • success.jsp
Logout
  • ShiroController
@Controller@RequestMapping("/shiro")public class ShiroController {   	@RequestMapping("/login")	public String login(@RequestParam("username") String username, 			@RequestParam("password") String password){   		Subject currentUser = SecurityUtils.getSubject();				if (!currentUser.isAuthenticated()) {   			// 把用户名和密码封装为 UsernamePasswordToken 对象            UsernamePasswordToken token = new UsernamePasswordToken(username, password);            // rememberme            token.setRememberMe(true);            try {               	System.out.println("token.hashCode() = " + token.hashCode());            	// 执行登录                currentUser.login(token);            }             // ... catch more exceptions here (maybe custom ones specific to your application?            // 所有认证时异常的父类            catch (AuthenticationException ae) {                   //unexpected condition?  error?            	System.out.println("登录失败: " + ae.getMessage());            }        }				return "redirect:/success.jsp";	}	}
  • 测试效果
    • 测试访问其他页面:无法访问,返回login.jsp
    • 测试用户名输入:unknown,打印:登录失败: 用户不存在!
    • 测试输入用户名:aa、密码:123456(即定义的Realm中的密码),登陆成功

3.3 密码加密配置

  • 将前台获取的密码进行加密:修改 spring-shiro.xml 配置的 Realm
  • 修改自定义Realm
public class ShiroRealm extends AuthenticatingRealm{   	@Override	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {   		//前面不变..				//6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo		//1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象		Object principal = username;		//2). credentials: 密码		Object credentials = "038bdaf98f2037b31f1e75b5b4c9b26e"; //123456采用MD5加密后的结构 		//3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可		String realmName = getName();		//4). 盐值		ByteSource credentialsSalt = ByteSource.Util.bytes(username);				SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);		return info;	}}
  • 原理
//shiro-core.jar包下package org.apache.shiro.authc;public class UsernamePasswordToken {   	public char[] getPassword() {           return password; // 打断点    }}//不断下一步,会来到equals方法,进行密码比对package org.apache.shiro.authc.credential;public class HashedCredentialsMatcher extends SimpleCredentialsMatcher {   	@Override    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {           Object tokenHashedCredentials = hashProvidedCredentials(token, info);        Object accountCredentials = getCredentials(info);        return equals(tokenHashedCredentials, accountCredentials);    }}

3.4 配置多个Realm

  • 增加新的自定义的Realm,使用SHA1加密,其他不变
public class ShiroRealm2 extends AuthenticatingRealm{   		/**	 * token:是SpringMVC从请求中获取的	 */	@Override	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {   		System.out.println("token.hashCode() = " + token.hashCode());		System.out.println("ShiroRealm2");		//1. 把 AuthenticationToken 转换为 UsernamePasswordToken 		UsernamePasswordToken upToken = (UsernamePasswordToken) token;				//2. 从 UsernamePasswordToken 中来获取 username		String username = upToken.getUsername();				//3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录		System.out.println("用户名:"+username);				//4. 若用户不存在, 则可以抛出 UnknownAccountException 异常		if("unknown".equals(username)){   			throw new UnknownAccountException("用户不存在!");		}				//5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常 		if("locked".equals(username)){   			throw new LockedAccountException("用户被锁定!");		}				//6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo		//1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象		Object principal = username;		//2). credentials: 密码		Object credentials = "ce2f6417c7e1d32c1d81a797ee0b499f87c5de06"; //123456		//3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可		String realmName = getName();		//4). 盐值		ByteSource credentialsSalt = ByteSource.Util.bytes(username);				SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);		return info;	}	}
  • 修改spring-shiro.xml
  • 原理
//controllercurrentUser.login(token);//调用Subject接口的login方法public interface Subject {   	void login(AuthenticationToken token) throws AuthenticationException;}//去找login的实现方法,这里调用securityManager.login()方法public class DelegatingSubject implements Subject {   	public void login(AuthenticationToken token) throws AuthenticationException {           clearRunAsIdentitiesInternal();        Subject subject = securityManager.login(this, token);        //...}//来到SecurityManager接口public interface SecurityManager extends Authenticator, Authorizer, SessionManager {   	Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException;}//找对应实现类,调用authenticate()方法public class DefaultSecurityManager extends SessionsSecurityManager {   	public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {           AuthenticationInfo info;        try {               info = authenticate(token);        }         //...    }}//继续进入public abstract class AuthenticatingSecurityManager extends RealmSecurityManager {   	public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {           return this.authenticator.authenticate(token);    }}//找authenticate()方法实现类,这里执行doAuthenticate()方法public abstract class AbstractAuthenticator implements Authenticator, LogoutAware {   	public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {   		//...        AuthenticationInfo info;        try {               info = doAuthenticate(token);            //...    }}//找doAuthenticate()实现方法public abstract class AbstractAuthenticator implements Authenticator, LogoutAware {   	protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token)            throws AuthenticationException;}//ModularRealmAuthenticator.class中getRealms()获取到的是Realm的集合public class ModularRealmAuthenticator extends AbstractAuthenticator {   	//263行	protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {           assertRealmsConfigured();        Collection
realms = getRealms(); if (realms.size() == 1) { //单个Realms认证 return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { //多个Realms认证 return doMultiRealmAuthentication(realms, authenticationToken); } } //198行 protected AuthenticationInfo doMultiRealmAuthentication(Collection
realms, AuthenticationToken token) { //选择认证策略 AuthenticationStrategy strategy = getAuthenticationStrategy(); AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token); //...}

3.5 授权

  • 增加user.jsp
  • 增加admin.jsp
  • 修改success.jsp
	

成功!

Logout User Page Admin page
  • 修改自定义Realm:模拟分别让user、admin登陆系统,密码都是123456
public class ShiroRealm extends AuthenticatingRealm{   	@Override	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {   		//...		Object credentials = null;		if("admin".equals(username)){   			credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";//123456加盐:admin、加密:MD5		}else if("user".equals(username)){   			credentials = "098d2c478e9c11555ce2823231e02ec1";//123456加盐:user、加密:MD5		}		//...	}}
  • 测试:登陆(用户名:user、密码:123456),登陆成功,可以访问user.jsp、admin.jsp
  • 修改spring-shiro.xml,设置user.jsp、admin.jsp的访问权限
/login.jsp = anon /shiro/login = anon /shiro/logout = logout /user.jsp = roles[user] /admin.jsp = roles[admin] # everything else requires authentication: /** = authc
  • 测试:登陆(用户名:user、密码:123456),登陆成功,不可以访问user.jsp、admin.jsp,会跳转到unauthorized.jsp
  • 通过以下原理分析,得出自定义Realm需要实现AuthorizingRealm,之前实现的是AuthenticatingRealm,所以修改ShiroRealm.java
public class ShiroRealm extends AuthorizingRealm{   		/**	 * 1.认证方法	 * token:是SpringMVC从请求中获取的	 */	@Override	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {   		System.out.println("token.hashCode() = " + token.hashCode());		//1. 把 AuthenticationToken 转换为 UsernamePasswordToken 		UsernamePasswordToken upToken = (UsernamePasswordToken) token;				//2. 从 UsernamePasswordToken 中来获取 username		String username = upToken.getUsername();				//3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录		System.out.println("用户名:"+username);				//4. 若用户不存在, 则可以抛出 UnknownAccountException 异常		if("unknown".equals(username)){   			throw new UnknownAccountException("用户不存在!");		}				//5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常 		if("locked".equals(username)){   			throw new LockedAccountException("用户被锁定!");		}				//6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo		//1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象		Object principal = username;		//2). credentials: 从数据库中获取密码,以下是在本地模拟		Object credentials = null;		if("admin".equals(username)){   			credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";//123456加盐:admin、加密:MD5		}else if("user".equals(username)){   			credentials = "098d2c478e9c11555ce2823231e02ec1";//123456加盐:user、加密:MD5		}		//3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可		String realmName = getName();		//4). 盐值		ByteSource credentialsSalt = ByteSource.Util.bytes(username);				SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);		return info;	}			/**	 * 2.授权会被shiro回调的方法	 */	@Override	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {   		//1. 从 PrincipalCollection 中来获取登录用户的信息		Object principal = principals.getPrimaryPrincipal();				//2. 利用登录用户的信息获取当前用户的角色或权限(可能需要查询数据库)		Set
roles = new HashSet<>(); roles.add("user"); // 模拟:所有用户都被赋予user角色 if("admin".equals(principal)){ roles.add("admin"); // 模拟:只有admin登陆后才有admin角色 } //3. 创建 SimpleAuthorizationInfo, 并设置其 reles 属性. SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles); //4. 返回 SimpleAuthorizationInfo 对象. return info; }}
  • 测试
    • 登陆【user、123456】,只能访问user.jsp
    • 登陆【admin、123456】,能访问user.jsp、admin.jsp
  • 原理(分析得出,自定义Realm需要实现AuthorizingRealm的doGetAuthorizationInfo方法)
//判断是否有权限:调用Subject.class下的hasRole()方法public interface Subject {   	boolean hasRole(String roleIdentifier);}//hasRole()的实现方法:调用securityManager的hasRole()方法public class DelegatingSubject implements Subject {   	public boolean hasRole(String roleIdentifier) {           return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);    }}//执行AuthorizingSecurityManager.class下的hasRole()方法public abstract class AuthorizingSecurityManager extends AuthenticatingSecurityManager {   	public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {           return this.authorizer.hasRole(principals, roleIdentifier);    }}//来到ModularRealmAuthorizer.class下的hasRole()方法public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware {   	public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {           assertRealmsConfigured();//验证realms不为空        for (Realm realm : getRealms()) {               if (!(realm instanceof Authorizer)) continue;            if (((Authorizer) realm).hasRole(principals, roleIdentifier)) {                   return true;            }        }        return false;    }}//这里将realm强转为Authorizer,去调用Authorizer接口下的hasRole()方法public interface Authorizer {       	boolean hasRole(PrincipalCollection subjectPrincipal, String roleIdentifier);}//hasRole()方法的具体实现方法为AuthorizingRealm.class下的hasRole()方法public abstract class AuthorizingRealm extends AuthenticatingRealm        implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware {       //572行,hasRole()方法执行getAuthorizationInfo	public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {           AuthorizationInfo info = getAuthorizationInfo(principal);        return hasRole(roleIdentifier, info);    }    //310行,执行doGetAuthorizationInfo	protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {   		//...		if (info == null) {               info = doGetAuthorizationInfo(principals);                        //...        }	}	//399行,该方法是一个抽象方法,需要被实现【重要!】	protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);	//577行,执行hasRole	protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {           return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);    }}

3.6 权限注解

@RequiresAuthentication

表示当前Subject已经通过login 进行了身份验证;即Subject. isAuthenticated()返回true。

@RequiresUser

表示当前Subject已经身份验证或者通过记住我登录的。

@RequiresGuest

表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。

@RequiresRoles(value={“admin”, “user”}, logical= Logical.AND)

@RequiresRoles(value={“admin”})   
@RequiresRoles({“admin“})

表示当前Subject需要角色admin 和user。

@RequiresPermissions (value={“user:a”, “user:b”}, logical= Logical.OR)

表示当前Subject需要权限user:a或user:b。

3.6.1 不使用@Service注解

public class ShiroService {   		@RequiresRoles({   "admin"})	public void testMethod(){   		System.out.println("testMethod, time: " + new Date());	}	}

spring.xml中将ShiroService添加到IOC容器

测试注解使用:必须角色admin才能执行testMethod();如果以【user、123456】登陆,无法执行testMethod(),会报错Subject does not have role [admin];以【admin、123456】登陆,可以执行testMethod()

3.6.2 使用@Service注解

坑:shiro注解不生效原因:官方说明shiro和spring集成时,spring-shiro.xml需要被spring.xml引用,但是集成springmvc时,spring-shiro.xml中关于开启注解的部分需要声明在spring-mvc.xml中

@Servicepublic class ShiroService {   		@RequiresRoles({   "admin"})	public void testMethod(){   		System.out.println("testMethod, time: " + new Date());	}	}

3.6.3 使用Spring声明式异常处理没有权限的异常

ExceptionHandlerControllerAdvice

3.7 从数据库中获取资源和权限

之前采用的方式:在spring-shiro.xml中配置

//...
/login.jsp = anon /shiro/login = anon /shiro/logout = logout /user.jsp = roles[user] /admin.jsp = roles[admin] # everything else requires authentication: /** = authc

实际上是调用了ShiroFilterFactoryBean.class的setFilterChainDefinitions(String definitions)方法,而经过debug,发现setFilterChainDefinitionMap()方法传入的是LinkedHashMap,即将上述filterChainDefinitions中的values封装到Map中。

public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor {   	public void setFilterChainDefinitions(String definitions) {           Ini ini = new Ini();        ini.load(definitions);        //did they explicitly state a 'urls' section?  Not necessary, but just in case:        Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);        if (CollectionUtils.isEmpty(section)) {               //no urls section.  Since this _is_ a urls chain definition property, just assume the            //default section contains only the definitions:            section = ini.getSection(Ini.DEFAULT_SECTION_NAME);        }        setFilterChainDefinitionMap(section);    }    public void setFilterChainDefinitionMap(Map
filterChainDefinitionMap) { this.filterChainDefinitionMap = filterChainDefinitionMap; }}

所以优化spring-shiro.xml:

//...

新建FilterChainDefinitionMapBuilder.java

public class FilterChainDefinitionMapBuilder {   	public LinkedHashMap
buildFilterChainDefinitionMap(){ LinkedHashMap
map = new LinkedHashMap<>(); map.put("/login.jsp", "anon"); map.put("/shiro/login", "anon"); map.put("/shiro/logout", "logout"); //访问user.jsp,需要经过认证authc,并且还具有user权限 map.put("/user.jsp", "authc,roles[user]"); map.put("/admin.jsp", "authc,roles[admin]"); //如果开启rememberme,只需要有user角色就可以访问,无需认证 map.put("/success.jsp", "user"); map.put("/**", "authc"); return map; } }

3.8 会话管理

3.9 缓存管理

3.10 Remember Me

controller:设置token.setRememberMe(true);

@Controller@RequestMapping("/shiro")public class ShiroController {   	@RequestMapping("/login")	public String login(@RequestParam("username") String username, 			@RequestParam("password") String password){   		Subject currentUser = SecurityUtils.getSubject();				if (!currentUser.isAuthenticated()) {   			// 把用户名和密码封装为 UsernamePasswordToken 对象            UsernamePasswordToken token = new UsernamePasswordToken(username, password);            // rememberme            token.setRememberMe(true);            //...	}	}

spring-shiro.xml:增加设置rememberme失效时间

4. SpringBoot整合教程

附录1:新建Spring工程

附录2:新建SpringBoot工程

上一篇:SSM中MyBatis使用XML配置文件版和注解版(eclipse)
下一篇:SpringBoot中使用Mybatis访问MySQL数据库(使用xml方式)

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月01日 16时09分07秒