- 一、认识Shiro
- 1、什么是Shiro?
- 2、有哪些功能?
- 3、Shiro架构(外部)
- 4、Shiro架构(内部)
- 二、授权方式
- 5.1、三种授权方式
- 5.2、授权流程
- 三、认证方式
- Realm:域
- 自定义Realm
- 四、Shiro InI配置(通常直接使用ShiroConfig)
- 1、INI配置
- 2、InI配置中的四大类
- 五、Shiro编码加密
- 1、散列算法
- 2、加密/解密
- 方式一
- 方式二
- 3、加密登录处理 HashedCredentialsMatcher方式
- 六、Shiro 的默认Filter
- 示例:
- 七、shiro注解权限控制-5个权限注解
- 八、示例Demo1(通过自定义token处理)
- 1、用户的角色与权限
- 2、编写ShiroConfig
- 3、自定义Realm
- 4、测试接口
- 5、登录处理
- 九、示例Demo2 (shiro直接处理用户名密码,并实现记住我、md5加密和缓存)
- 1、用户的角色与权限
- 2、编写ShiroConfig
- 3、自定义Realm
- 4、测试接口
- 5、登录处理
- Apache Shiro 是一个Java 的安全(权限)框架。
- Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环
境。 - Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等。
- Authentication:身份认证、登录,验证用户是不是拥有相应的身份;
- Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限,即判断用户能否
进行什么 *** 作,如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否
具有某个权限! - Session Manager:会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都
在会话中;会话可以是普通的JavaSE环境,也可以是Web环境; - Cryptography:加密,保护数据的安全性,如密码加密存储到数据库中,而不是明文存储;
- Web Support:Web支持,可以非常容易的集成到Web环境;
- Caching:缓存,比如用户登录后,其用户信息,拥有的角色、权限不必每次去查,这样可以提高
效率 - Concurrency:Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限
自动的传播过去 - Testing:提供测试支持;
- Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
- Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
从外部来看shiro,即从应用程序角度来观察如何使用shiro完成工作:
- Subject:代表当前"用户"。与当前应用程序交互的任何东西都是Subject,如爬虫、机器人。所有的Subject 都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager。Subject 是一个门面,SecurityManager 是实际的执行者。
- SecurityManager:与安全有关的 *** 作都会与SecurityManager交互。它管理者所有Subject,是Shiro的核心,负责与其他组件进行交互。
- Realm: Shiro从Realm中获取安全数据(用户、角色、权限)。SecurityManager需要从Realm中获取响应的用户信息进行比较用户身份是否合法,也需要从Realm中得到用户相应的角色/权限进行验证,以确定用户是否能够 *** 作。
- Subject:任何可以与应用交互的 用户;
- Security Manager:相当于SpringMVC中的DispatcherServlet;是Shiro的心脏,所有具体的交互
都通过Security Manager进行控制,它管理者所有的Subject,且负责进行认证,授权,会话,及
缓存的管理。 - Authenticator:负责Subject认证,是一个扩展点,可以自定义实现;可以使用认证策略
(Authentication Strategy),即什么情况下算用户认证通过了; - Authorizer:授权器,即访问控制器,用来决定主体是否有权限进行相应的 *** 作;即控制着用户能
访问应用中的那些功能; - Realm:可以有一个或者多个的realm,可以认为是安全实体数据源,即用于获取安全实体的,可
以用JDBC实现,也可以是内存实现等等,由用户提供;所以一般在应用中都需要实现自己的realm - SessionManager:管理Session生命周期的组件,而Shiro并不仅仅可以用在Web环境,也可以用
在普通的JavaSE环境中 - CacheManager:缓存控制器,来管理如用户,角色,权限等缓存的;因为这些数据基本上很少改
变,放到缓存中后可以提高访问的性能; - Cryptography:密码模块,Shiro 提供了一些常见的加密组件用于密码加密,解密等
流程如下:
- 1、首先调用 Subject.isPermitted*/hasRole*接口,其会委托给 SecurityManager,而 SecurityManager 接着会委托给 Authorizer;
- 2、Authorizer 是真正的授权者,如果我们调用如 isPermitted(“user:view”),其首先会通过 PermissionResolver 把字符串转换成相应的 Permission 实例;
- 3、在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;
- 4、Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个 Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted*/hasRole* 会返回 true,否则返回 false 表示授权失败。
ModularRealmAuthorizer 进行多 Realm 匹配流程:
- 首先检查相应的 Realm 是否实现了实现了 Authorizer;
- 如果实现了 Authorizer,那么接着调用其相应的 isPermitted*/hasRole* 接口进行匹配;
- 如果有一个 Realm 匹配那么将返回 true,否则返回 false。
三、认证方式 Realm:域如果 Realm 进行授权的话,应该继承 AuthorizingRealm,其流程是:
- 如果调用 hasRole*,则直接获取 AuthorizationInfo.getRoles() 与传入的角色比较即可;首先如果调用如 isPermitted(“user:view”),首先通过 PermissionResolver 将权限字符串转换成相应的 Permission 实例,默认使用 WildcardPermissionResolver,即转换为通配符的 WildcardPermission;
- 通过 AuthorizationInfo.getObjectPermissions() 得到 Permission 实例集合;通过 AuthorizationInfo.getStringPermissions() 得到字符串集合并通过 PermissionResolver 解析为 Permission 实例;然后获取用户的角色,并通过 RolePermissionResolver 解析角色对应的权限集合(默认没有实现,可以自己提供);
- 接着调用 Permission.implies(Permission p) 逐个与传入的权限比较,如果有匹配的则返回 true,否则 false。
Shiro 从 Realm获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行 *** 作;可以把 Realm 看成 DataSource
String getName(); //返回一个唯一的Realm名字 boolean supports(AuthenticationToken token); //判断此Realm是否支持此Token AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException; //根据Token获取认证信息自定义Realm
public class MyRealm implements Realm { @Override public String getName() { return "myrealm"; } @Override public boolean supports(AuthenticationToken token) { //仅支持UsernamePasswordToken类型的Token return token instanceof UsernamePasswordToken; } @Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); //得到用户名 String password = new String((char[])token.getCredentials()); //得到密码 if(!"zhang".equals(username)) { throw new UnknownAccountException(); //如果用户名错误 } if(!"123".equals(password)) { throw new IncorrectCredentialsException(); //如果密码错误 } //如果身份认证验证成功,返回一个AuthenticationInfo实现; return new SimpleAuthenticationInfo(username, password, getName()); } }四、Shiro InI配置(通常直接使用ShiroConfig) 1、INI配置
ini 配置文件类似于 Java 中的 properties(key=value),不过提供了将 key/value 分类的特性,key 是每个部分不重复即可,而不是整个配置文件。如下是 INI 配置分类:
[main] #提供了对根对象securityManager及其依赖的配置 securityManager=org.apache.shiro.mgt.DefaultSecurityManager ………… securityManager.realms=$jdbcRealm [users] #提供了对用户/密码及其角色的配置,用户名=密码,角色1,角色2 username=password,role1,role2 [roles] #提供了角色及权限之间关系的配置,角色=权限1,权限2 role1=permission1,permission2 [urls] #用于web,提供了对web url拦截相关的配置,url=拦截器[参数],拦截器 /index.html = anon /admin @Configuration public class ShiroConfig { @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); // 登录配置 shiroFilter.setLoginUrl("/login"); shiroFilter.setSuccessUrl("/"); shiroFilter.setUnauthorizedUrl("/error/403"); // 自定义过滤器 MapfiltersMap = new linkedHashMap<>(); filtersMap.put("mlfc", new MyLoginFilter()); shiroFilter.setFilters(filtersMap); // 拦截配置 Map filterChainDefinitions = new linkedHashMap<>(); filterChainDefinitions.put("/assets @PostMapping("/login") @ResponseBody public R login(HttpServletRequest request, String username, String password, String code, boolean rememberMe) { if (StringUtil.isBlank(username, password)) { return R.failed("账号或密码不能为空"); } String sessionCode = (String) request.getSession().getAttribute("captcha"); if (code == null || !sessionCode.equals(code.trim().toLowerCase())) { return R.failed("验证码不正确"); } try { UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); SecurityUtils.getSubject().login(token); return R.succeed("登录成功"); } catch (UnknownAccountException e) { return R.failed("用户不存在"); } catch (IncorrectCredentialsException e) { return R.failed("密码错误"); } catch (ExcessiveAttemptsException eae) { return R.failed(" *** 作频繁,请稍后再试"); } }
- shiro默认登录过期时间是30分钟
//永不过期,在登陆最开始加上 SecurityUtils.getSubject().getSession().setTimeout(-1000L); //其他时间 单位毫秒 SecurityUtils.getSubject().getSession().setTimeout(1800000);六、Shiro 的默认Filter
- /admin
@Configuration
public class ShiroConfig {
//SecurityManager 是 Shiro 架构的核心,通过它来链接Realm和用户(文档中称之为Subject.)
@Bean("securityManager")
public SecurityManager securityManager(AuthRealm authRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(authRealm); //将Realm注入到SecurityManager中。
return securityManager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
//auth过滤
Map
filters = new HashMap<>(); filters.put("auth", new AuthFilter()); shiroFilter.setFilters(filters); Map filterMap = new linkedHashMap<>(); //authc表示需要验证身份才能访问,还有一些比如anon表示不需要验证身份就能访问等。 // anno匿名访问 auth验证 filterMap.put("/webjars @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } //负责管理shiro的生命周期,项目中不加lifecyclebeanpostprocessor也没问题 @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } } 3、自定义Realm @Component public class AuthRealm extends AuthorizingRealm { @Autowired private ShiroService shiroService; private String salt = "lyp"; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //1. 从 PrincipalCollection 中来获取登录用户的信息 User user = (User) principals.getPrimaryPrincipal(); //Integer userId = user.getUserId(); //2.添加角色和权限 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); for (Role role : user.getRoles()) { //2.1添加角色 simpleAuthorizationInfo.addRole(role.getRoleName()); for (Permission permission : role.getPermissions()) { //2.1.1添加权限 simpleAuthorizationInfo.addStringPermission(permission.getPermission()); } } return simpleAuthorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取token,既前端传入的token String accessToken = (String) token.getPrincipal(); //1. 根据accessToken,查询用户信息 SysToken tokenEntity = shiroService.findByToken(accessToken); //2. token失效 if (tokenEntity == null || tokenEntity.getExpireTime().isBefore(LocalDateTime.now())) { throw new IncorrectCredentialsException("token失效,请重新登录"); } //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录 User user = shiroService.findByUserId(tokenEntity.getUserId()); //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常 if (user == null) { throw new UnknownAccountException("用户不存在!"); } //5. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo SimpleAuthenticationInfo info = new SimpleAuthenticationInfo( user, //用户 accessToken, this.getName()); //Realm name return info; } }
4、测试接口@Api(tags = "测试") @RestController public class TestController { @RequiresPermissions({"save"}) @PostMapping("/save") public Map
5、登录处理save(@RequestHeader("token")String token) { System.out.println("save"); Map map = new HashMap (); map.put("status", 200); map.put("msg", "当前用户有save的权力"); return map; } @RequiresPermissions({"delete"}) @DeleteMapping("/delete") public Map delete(@RequestHeader("token")String token) { System.out.println("delete"); Map map = new HashMap (); map.put("status", 200); map.put("msg", "当前用户有delete的权力"); return map; } @RequiresPermissions({"update"}) @PutMapping("update") public Map update(@RequestHeader("token")String token) { System.out.println("update"); Map map = new HashMap (); map.put("status", 200); map.put("msg", "当前用户有update的权力"); return map; } @RequiresPermissions({"select"}) @GetMapping("select") public Map select(@RequestHeader("token")String token) { System.out.println("select"); Map map = new HashMap (); map.put("status", 200); map.put("msg", "当前用户有select的权力"); return map; } @RequiresRoles({"vip"}) @GetMapping("/vip") public Map vip(@RequestHeader("token")String token) { System.out.println("vip"); Map map = new HashMap (); map.put("status", 200); map.put("msg", "当前用户有VIP角色"); return map; } @RequiresRoles({"svip"}) @GetMapping("/svip") public Map svip(@RequestHeader("token")String token) { System.out.println("svip"); Map map = new HashMap (); map.put("status", 200); map.put("msg", "当前用户有SVIP角色"); return map; } @RequiresRoles({"p"}) @GetMapping("/p") public Map p(@RequestHeader("token")String token) { System.out.println("p"); Map map = new HashMap (); map.put("status", 200); map.put("msg", "当前用户有P角色"); return map; } } @Api(tags = "Shiro权限管理") @RestController public class ShiroController { private final ShiroService shiroService; public ShiroController(ShiroService shiroService) { this.shiroService = shiroService; } @ApiOperation(value = "登陆", notes = "参数:用户名 密码") @PostMapping("/sys/login") public Map
login(@RequestBody @Validated LoginDTO loginDTO, BindingResult bindingResult) { Map result = new HashMap<>(); if (bindingResult.hasErrors()) { result.put("status", 400); result.put("msg", bindingResult.getFieldError().getDefaultMessage()); return result; } String username = loginDTO.getUsername(); String password = loginDTO.getPassword(); //用户信息 User user = shiroService.findByUsername(username); //账号不存在、密码错误 if (user == null || !user.getPassword().equals(password)) { result.put("status", 400); result.put("msg", "账号或密码有误"); } else { //生成token,并保存到数据库 result = shiroService.createToken(user.getUserId()); result.put("status", 200); result.put("msg", "登陆成功"); } return result; } @ApiOperation(value = "登出", notes = "参数:token") @PostMapping("/sys/logout") public Map logout(@RequestHeader("token")String token) { Map result = new HashMap<>(); shiroService.logout(token); result.put("status", 200); result.put("msg", "您已安全退出系统"); return result; } } 通过自定义过滤器拦截,拒绝访问的请求通过executeLogin方法,校验是否能通过
** * Shiro自定义auth过滤器 * */ @Component public class AuthFilter extends AuthenticatingFilter { // 定义jackson对象 private static final ObjectMapper MAPPER = new ObjectMapper(); @Override protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception { //获取请求token String token = TokenUtil.getRequestToken((HttpServletRequest) request); return new AuthToken(token); } @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) { return true; } return false; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { //获取请求token,如果token不存在,直接返回 String token = TokenUtil.getRequestToken((HttpServletRequest) request); if (StringUtils.isBlank(token)) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtil.getOrigin()); httpResponse.setCharacterEncoding("UTF-8"); Map
result = new HashMap<>(); result.put("status", 403); result.put("msg", "请先登录"); String json = MAPPER.writevalueAsString(result); httpResponse.getWriter().print(json); return false; } return executeLogin(request, response); } @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setContentType("application/json;charset=utf-8"); httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtil.getOrigin()); httpResponse.setCharacterEncoding("UTF-8"); try { //处理登录失败的异常 Throwable throwable = e.getCause() == null ? e : e.getCause(); Map result = new HashMap<>(); result.put("status", 403); result.put("msg", "登录凭证已失效,请重新登录"); String json = MAPPER.writevalueAsString(result); httpResponse.getWriter().print(json); } catch (IOException e1) { } return false; } } 查看源码,exeuteLogin内部使用的就是shiro的登录方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i8iUuZsq-1640827044142)(C:UsersASUSAppDataRoamingTyporatypora-user-imagesimage-20211229163935965.png)]
自定义token类要继承UsernamePasswordToken
public class AuthToken extends UsernamePasswordToken { private String token; public AuthToken(String token) { this.token = token; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } }
这里不继承 AuthenticationToken,因为getAuthenticationTokenClass()实际上获取到的是UsernamePasswordToken.class
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7A4m85aa-1640827044142)(C:UsersASUSAppDataRoamingTyporatypora-user-imagesimage-20211229164805817.png)]
九、示例Demo2 (shiro直接处理用户名密码,并实现记住我、md5加密和缓存) 1、用户的角色与权限用户 角色 权限 adminadmin[查看文件,拷贝文件、移动文件、重命名文件、下载文件、删除文件、上传文件、目录管理、创建目录、文件打分、评论文件、查看得分] lypuser[查看文件,拷贝文件、下载文件、上传文件、目录管理、评论文件、查看得分] 2、编写ShiroConfig@Configuration public class ShiroConfig { @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); // 登录配置 shiroFilter.setLoginUrl("/login"); shiroFilter.setSuccessUrl("/"); shiroFilter.setUnauthorizedUrl("/error/403"); // 自定义过滤器 Map
3、自定义RealmfiltersMap = new linkedHashMap<>(); filtersMap.put("mlfc", new MyLoginFilter()); shiroFilter.setFilters(filtersMap); // 拦截配置 Map filterChainDefinitions = new linkedHashMap<>(); filterChainDefinitions.put("/assets @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager()); return advisor; } @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean("shiroDialect") public ShiroDialect getShiroDialect() { return new ShiroDialect(); } //cookie对象 @Bean public Simplecookie rememberMecookie() { Simplecookie simplecookie = new Simplecookie("rememberMe"); simplecookie.setMaxAge(259200); return simplecookie; } //cookie管理对象 处理记住我功能 @Bean public cookieRememberMeManager rememberMeManager() { cookieRememberMeManager cookieRememberMeManager = new cookieRememberMeManager(); cookieRememberMeManager.setcookie(rememberMecookie()); cookieRememberMeManager.setCipherKey(base64.decode("2AvVhdsgUs0FSA3SDFAdag==")); return cookieRememberMeManager; } } public class MyRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Autowired private RoleAuthMapper roleAuthMapper; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { User user = (User) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); List
4、测试接口roleList = userRoleMapper.selectRoleCodesById(user.getId()); List authList = roleAuthMapper.selectAuthCodesByRoleCodes(roleList); Set roleSet = new HashSet<>(roleList); Set authSet = new HashSet<>(authList); authorizationInfo.setRoles(roleSet); authorizationInfo.setStringPermissions(authSet); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); // 往数据库中查询用户 User user = userMapper.selectOne(new QueryWrapper ().lambda().eq(User::getUsername, username)); if (user == null) { // 账号不存在 throw new UnknownAccountException(); } // 密码验证shiro处理 return new SimpleAuthenticationInfo( user, //用户 user.getPassword(), //密码 ByteSource.Util.bytes("lyp"), // 加密传入盐值 getName());//Realm name ); } } @RestController public class ScoreController extends baseController{ @Autowired ScoreServiceImpl scoreService; @Autowired UserService userService; @RequiresPermissions("file:score") @PostMapping("/addScore") public R addScore(Score score){ System.out.println("获取结果:"+score); score.setUserId(getLoginUserId()); if(scoreService.addScore(score)){ return R.succeed("打分成功"); } return R.failed("打分失败"); } @RequiresPermissions("file:check") @GetMapping("/getScore/{fileId}") public R getScore(@PathVariable Long fileId){ Score score = scoreService.queryScoreByFId(fileId); return R.succeed(score,"查询成功"); } }
5、登录处理@PostMapping("/login") @ResponseBody public R login(HttpServletRequest request, String username, String password, String code, boolean rememberMe) { if (StringUtil.isBlank(username, password)) { return R.failed("账号或密码不能为空"); } String sessionCode = (String) request.getSession().getAttribute("captcha"); if (code == null || !sessionCode.equals(code.trim().toLowerCase())) { return R.failed("验证码不正确"); } //获取当前用户 Subject subject = SecurityUtils.getSubject(); //封装用户的登录数据 UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); try { //执行登录方法,如果没有异常就说明OK了 subject.login(token); return R.succeed("登录成功"); } catch (UnknownAccountException e) { return R.failed("用户不存在"); } catch (IncorrectCredentialsException e) { return R.failed("密码错误"); } catch (ExcessiveAttemptsException eae) { return R.failed(" *** 作频繁,请稍后再试"); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)