首页 文章 精选 留言 我的

精选列表

搜索[表单验证],共10009篇文章
优秀的个人博客,低调大师

Shiro | 实现权限验证完整版

写在前面的话 提及权限,就会想到安全,是一个十分棘手的话题。这里只是作为学校Shiro的一个记录,而不是,权限就应该这样设计之类的。 Shiro框架 1、Shiro是基于Apache开源的强大灵活的开源安全框架。 2、Shiro提供了 认证,授权,企业会话管理、安全加密、缓存管理。 3、Shiro与Security对比 4、Shiro整体架构 5、特性 6、认证流程 认证 当我们理解Shiro之后,我们就能比较容易梳理出认证流程,大概就是下面这样子。 我们来看一段测试代码: // 1.构建SecurityManager环境 DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(simpleAccountRealm); // 2.主体提交认证请求 SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); // 3.认证 UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin"); subject.login(token); System.out.println("是否认证:" + subject.isAuthenticated()); // 4.退出 subject.logout(); System.out.println("是否认证:" + subject.isAuthenticated()); 我们发现Shiro真正帮我们做的就是认证这一步,那他到底是如何去认证的呢? 我们把我们登录的代码完善一下: /** * 登录操作,返回登录认证信息 * @return 登录结果 */ public String login() { try { DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(simpleAccountRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin"); subject.login(token); if (subject.isAuthenticated()) return "登录成功"; } catch (IncorrectCredentialsException e1) { e1.printStackTrace(); return "密码错误"; } catch (LockedAccountException e2) { e2.printStackTrace(); return "登录失败,该用户已被冻结"; } catch (AuthenticationException e3) { e3.printStackTrace(); return "该用户不存在"; } catch (Exception e) { e.printStackTrace(); } return "登录失败"; } Realm 1、IniReam 配置文件 user.ini [users] Mark=admin,admin [roles] admin=user:add,user:delete,user:update,user:select 测试代码 // IniRealm 测试 @Test public void testAuthenticationIniRealm () { IniRealm iniRealm = new IniRealm("classpath:user.ini"); DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(iniRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456"); subject.login(token); System.out.println("是否认证:" + subject.isAuthenticated()); subject.checkRole("admin"); subject.checkPermission("user:delete"); } 2、JdbcRealm 这里有两种方案,使用Shiro为我们提供了SQL语句,或者我们自己写SQL语句。 第一种: // JdbcRealm 测试 Shiro SQL @Test public void testAuthenticationShiroSQL() { JdbcRealm jdbcRealm = new JdbcRealm(); jdbcRealm.setDataSource(druidDataSource); jdbcRealm.setPermissionsLookupEnabled(true); DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(jdbcRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("xfsy", "xfsy2018"); subject.login(token); System.out.println("是否认证:" + subject.isAuthenticated()); subject.checkRole("user"); subject.checkPermission("user:select"); } 第二种: // JdbcRealm 测试 Custom SQL @Test public void testAuthenticationCustomSQL() { JdbcRealm jdbcRealm = new JdbcRealm(); jdbcRealm.setDataSource(druidDataSource); jdbcRealm.setPermissionsLookupEnabled(true); /** * @see org.apache.shiro.realm.jdbc.JdbcRealm */ String sql = "select pwd from t_user where user_name = ?"; jdbcRealm.setAuthenticationQuery(sql); DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); defaultSecurityManager.setRealm(jdbcRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("test", "123"); subject.login(token); System.out.println("是否认证:" + subject.isAuthenticated()); } 3、自定义Realm 在上面我们已经看过了 JdbcRealm,所以我们也可以依葫芦画瓢自定义Ramlm。 第一步:继承 AuthorizingRealm 第二步:实现认证方法 第三步:实现授权方法 通过AuthorizingRealm,我们完全按照自己的需求实现自己的业务逻辑。 import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /** * @author Wenyi Feng * @since 2018-10-22 */ public class CustomRealmTest extends AuthorizingRealm { /** * Retrieves the AuthorizationInfo for the given principals from the underlying data store. When returning * an instance from this method, you might want to consider using an instance of * {@link org.apache.shiro.authz.SimpleAuthorizationInfo SimpleAuthorizationInfo}, as it is suitable in most cases. * * @param principals the primary identifying principals of the AuthorizationInfo that should be retrieved. * @return the AuthorizationInfo associated with this principals. * @see org.apache.shiro.authz.SimpleAuthorizationInfo */ // 授权 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } /** * Returns {@code true} if authentication caching should be utilized based on the specified * {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise. * <p/> * The default implementation simply delegates to {@link #isAuthenticationCachingEnabled()}, the general-case * authentication caching setting. Subclasses can override this to turn on or off caching at runtime * based on the specific submitted runtime values. * * @param token the submitted authentication token * @param info the {@code AuthenticationInfo} acquired from data source lookup via * {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)} * @return {@code true} if authentication caching should be utilized based on the specified * {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise. * @since 1.2 */ // 认证 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { return null; } } 可能Shiro提供的Realm并不能满足我们的实际开发需求,所以真正弄明白自定义Realm还是有很大帮助的,你觉得呢? 4、安全加密 明文密码? 好吧,我们看看Shiro为我们提供的加密方法。 // Md5Hash md5Hash = new Md5Hash("123456"); Md5Hash md5Hash = new Md5Hash("123456", "admin"); System.out.println(md5Hash.toString()); 那我们该怎么使用了? 在Realm认证中设置盐值 // 使用admin对密码进行加密 authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("admin")); 我们只需要告诉我们的Realm,需要对密码进行加密就可以了。 CustomRealm customRealm = new CustomRealm(); HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); // 加密类型 matcher.setHashAlgorithmName("md5"); // 加密次数 matcher.setHashIterations(1); customRealm.setCredentialsMatcher(matcher); 权限 1、Shiro为我们提供的权限 名称 说明 anon 不校验 authc 作校验 roles 需要具有指定角色(一个或多个)才能访问 perms 需要具有指定角色(一个或多个)才能访问 2、配置 <!-- 从上往下开始匹配 --> /login.html = anon /subLogin = anon <!--/testRole = roles["admin"]--> <!--/testRole1 = roles["admin", "admin1"]--> <!--/testPerms = perms["user:delete"]--> <!--/testPerms1 = perms["user:delete", "user:update"]--> 3、自定义权限认证 import org.apache.shiro.web.filter.authz.AuthorizationFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * @author Wenyi Feng * @since 2018-10-22 */ public class CustomAuthorizationFilter extends AuthorizationFilter { protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { return false; } } 另外,看一下 Shiro Filter 会话管理(Session) 会话管理,就是拿到Session之后,我们怎么处理。什么意思?分布式系统,需要共享Session。 import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; import java.io.Serializable; import java.util.Collection; /** * 自定义Session操作接口 * @author Wenyi Feng * @since 2018-10-22 */ public class CustomSessionDAO extends AbstractSessionDAO { // 创建Session protected Serializable doCreate(Session session) { return null; } // 读session protected Session doReadSession(Serializable sessionId) { return null; } // 修改session public void update(Session session) throws UnknownSessionException { } // 删除session public void delete(Session session) { } // 获取当前活动的session public Collection<Session> getActiveSessions() { return null; } } 缓存管理(Cache) 缓存管理同Session管理,可以这样说,session是一套系统的基础,缓存决定系统的优化级别,很重要。 另外,我们看一下,Shiro为我们设计的缓存接口。 package org.apache.shiro.cache; import java.util.Collection; import java.util.Set; public interface Cache<K, V> { V get(K var1) throws CacheException; V put(K var1, V var2) throws CacheException; V remove(K var1) throws CacheException; void clear() throws CacheException; int size(); Set<K> keys(); Collection<V> values(); } 自动登录 我们只需要为token设置RememberMe就可以了。 token.setRememberMe(user.getRememberMe()); 链接 [1] Shiro安全框架入门 [2] 本次测试代码:ShiroLearn

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册