一、环境准备
1、创建Maven项目,在pom.xml中添加依赖
xml
复制代码
<dependencies> <!-- Shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.14</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.14</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.3.14</version> </dependency> <!-- MyBatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> <!-- MySQL Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> </dependencies>
2、配置数据源和MyBatis
在src/main/resources目录下创建一个名为applicationContext.xml的Spring配置文件,并配置数据源和MyBatis。
xml
复制代码
<!-- 数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/my_database?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!-- MyBatis --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="com.example.model"/> <property name="mapperLocations" value="classpath*:mapper/*.xml"/> </bean> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory"/> </bean>
3、配置Shiro
在src/main/resources目录下创建一个名为shiro.ini的Shiro配置文件,并配置Shiro。
xml
复制代码
[main] # Realm配置 myRealm = com.example.shiro.MyRealm securityManager.realm = $myRealm # 编码器配置 hashedCredentialsMatcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher hashedCredentialsMatcher.hashAlgorithmName = SHA-256 hashedCredentialsMatcher.hashIterations = 1 myRealm.credentialsMatcher = $hashedCredentialsMatcher # 缓存配置 cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager securityManager.cacheManager = $cacheManager ehcacheManager.cacheManagerConfigFile = classpath:ehcache.xml cacheManager.cacheManager = $ehcacheManager # 过滤器配置 authc = org.apache.shiro.web.filter.authc.FormAuthenticationFilter authc.loginUrl = /login.jsp authc.successUrl = /index.jsp authc.usernameParam = username authc.passwordParam = password authc.rememberMeParam = rememberMe perms = org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter [urls] # anon表示不需要认证 # authc表示需要认证 # perms表示需要权限 /login.jsp = anon /logout = anon /index.jsp = authc,perms[user:view] /user/list = authc,perms[user:view] /user/add = authc,perms[user:add] /user/edit = authc,perms[user:edit] /user/delete = authc,perms[user:delete]
3、编写MyRealm
在com.example.shiro
包下创建一个名为MyRealm的类,并继承org.apache.shiro.realm.AuthorizingRealm
java
复制代码
public class MyRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); User user = (User) principalCollection.getPrimaryPrincipal(); List<String> permissions = userService.getPermissionsByUserId(user.getId()); authorizationInfo.addStringPermissions(permissions); return authorizationInfo; } /** * 认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; User user = userService.getUserByUsername(token.getUsername()); if (user == null) { throw new UnknownAccountException(); } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName()); return authenticationInfo; } }
4、编写UserService
在com.example.service包下创建一个名为UserService的接口,并定义获取用户信息和权限的方法。
java
复制代码
public interface UserService { User getUserByUsername(String username); List<String> getPermissionsByUserId(Long userId); }
在com.example.service.impl包下创建一个名为UserServiceImpl的类,并实现UserService接口。
java
复制代码
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private PermissionMapper permissionMapper; @Override public User getUserByUsername(String username) { return userMapper.getUserByUsername(username); } @Override public List<String> getPermissionsByUserId(Long userId) { return permissionMapper.getPermissionsByUserId(userId); } }
5、编写Controller
在com.example.controller包下创建一个名为UserController的类,并编写处理请求的方法。
java
复制代码
@Controller @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping("/list") @RequiresPermissions("user:view") public String list(Model model) { List<User> userList = userService.getUserList(); model.addAttribute("userList", userList); return "user/list"; } @RequestMapping("/add") @RequiresPermissions("user:add") public String add() { return "user/add"; } @RequestMapping("/edit/{id}") @RequiresPermissions("user:edit") public String edit(@PathVariable("id") Long id, Model model) { User user = userService.getUserById(id); model.addAttribute("user", user); return "user/edit"; } @RequestMapping("/update") @RequiresPermissions("user:edit") public String update(User user) { userService.updateUser(user); return "redirect:/user/list"; } @RequestMapping("/delete/{id}") @RequiresPermissions("user:delete") public String delete(@PathVariable("id") Long id) { userService.deleteUserById(id); return "redirect:/user/list"; } }
6、编写登录页面
在src/main/webapp下创建一个名为login.jsp的登录页面。
html
复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录</title> </head> <body> <form action="/login" method="post"> <input type="text" name="username" placeholder="用户名"><br> <input type="password" name="password" placeholder="密码"><br> <input type="checkbox" name="rememberMe">记住我<br> <button type="submit">登录</button> </form> </body> </html>
7、编写权限控制页面
在src/main/webapp下创建一个名为list.jsp的权限控制页面。
html
复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>用户列表</title> </head> <body> <table> <tr> <th>编号</th> <th>用户名</th> <th>姓名</th> <th>操作</th> </tr> <c:forEach items="${userList}" var="user"> <tr> <td>${user.id}</td> <td>${user.username}</td> <td>${user.name}</td> <td> <a href="/user/edit/${user.id}" ${hasPermission('user:edit') ? '' : 'style="display:none;"'}>编辑</a> <a href="/user/delete/${user.id}" ${hasPermission('user:delete') ? '' : 'style="display:none;"'}>删除</a> </td> </tr> </c:forEach> </table> <a href="/user/add" ${hasPermission('user:add') ? '' : 'style="display:none;"'}>新增</a> </body> </html>
8、配置ehcache.xml
在src/main/resources下创建一个名为ehcache.xml的Ehcache配置文件,并配置缓存。
xml
复制代码
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false" name="myCacheManager"> <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="true" diskPersistent="true" timeToIdleSeconds="120" timeToLiveSeconds="1200" diskExpiryThreadIntervalSeconds="120"/> <cache name="myCache1" maxElementsInMemory="5000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="1200" diskExpiryThreadIntervalSeconds="120"/> <cache name="myCache2" maxElementsInMemory="10000" eternal="false" overflowToDisk="true" timeToIdleSeconds="240" timeToLiveSeconds="2400" diskExpiryThreadIntervalSeconds="240"/> </ehcache>
9、编写Shiro配置文件
在src/main/resources下创建一个名为shiro.ini的Shiro配置文件,并配置相关信息。
xml
复制代码
[main] # 配置Realm,用于身份认证和授权 userRealm = org.apache.shiro.realm.jdbc.JdbcRealm userRealm.dataSource = $dataSource userRealm.permissionsLookupEnabled = true userRealm.authenticationQuery = SELECT password FROM user WHERE username = ? userRealm.userRolesQuery = SELECT role_name FROM user_role WHERE username = ? userRealm.permissionsQuery = SELECT permission FROM role_permission WHERE role_name = ? userRealm.saltStyle = COLUMN # 配置缓存 cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager cacheManager.cacheManagerConfigFile = classpath:ehcache.xml # 配置Session管理器 sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager sessionManager.globalSessionTimeout = 1800000 sessionManager.deleteInvalidSessions = true # 配置Cookie管理器 cookie = org.apache.shiro.web.servlet.SimpleCookie cookie.name = JSESSIONID cookie.path = / cookie.httpOnly = true cookie.maxAge = 1800000 # 配置SecurityManager,管理所有的Subject securityManager = org.apache.shiro.web.mgt.DefaultWebSecurityManager securityManager.realm = $userRealm securityManager.cacheManager = $cacheManager securityManager.sessionManager = $sessionManager securityManager.sessionManager.sessionIdCookie = $cookie # 配置过滤器,用于拦截请求 authc = org.apache.shiro.web.filter.authc.FormAuthenticationFilter authc.loginUrl = /login authc.successUrl = /user/list authc.usernameParam = username authc.passwordParam = password authc.rememberMeParam = rememberMe authc.rememberMeCookie = $cookie perms = org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter # 配置ShiroFilter,用于管理过滤器链 shiroFilter = org.apache.shiro.web.servlet.ShiroFilter shiroFilter.securityManager = $securityManager shiroFilter.loginUrl = /login shiroFilter.filterChainDefinitions = /user/list = authc, perms["user:view"] /user/add = authc, perms["user:add"] /user/edit/** = authc, perms["user:edit"] /user/delete/** = authc, perms["user:delete"] /** = anon [urls] # 配置不需要拦截的URL /login = anon /logout = anon
10、配置Spring容器
在src/main/resources下创建一个名为spring-context.xml的Spring配置文件,并配置相关信息。
xml
复制代码
<beans> <!-- 配置数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置MyBatis --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="typeAliasesPackage" value="com.example.demo.entity" /> <property name="mapperLocations" value="classpath:mapper/*.xml" /> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.demo.dao" /> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置Shiro --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/login" /> <property name="filterChainDefinitions"> <value> /user/list = authc, perms["user:view"] /user/add = authc, perms["user:add"] /user/edit/** = authc, perms["user:edit"] /user/delete/** = authc, perms["user:delete"] /** = anon </value> </property> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <bean id="defaultAdvisorAutoProxyCreator" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="jdbcRealm" /> <property name="sessionManager" ref="sessionManager" /> <property name="cacheManager" ref="cacheManager" /> </bean> <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="dataSource" ref="dataSource" /> <property name="authenticationQuery" value="SELECT password FROM user WHERE username = ?" /> <property name="userRolesQuery" value="SELECT role_name FROM user_role WHERE username = ?" /> <property name="permissionsQuery" value="SELECT permission FROM role_permission WHERE role_name = ?" /> <property name="saltStyle" value="COLUMN" /> </bean> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" /> </bean> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000" /> <property name="deleteInvalidSessions" value="true" /> <property name="sessionValidationSchedulerEnabled" value="false" /> <property name="sessionIdCookie" ref="simpleCookie" /> </bean> <bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="JSESSIONID" /> <property name="httpOnly" value="true" /> <property name="maxAge" value="1800000" /> <property name="path" value="/" /> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <bean id="defaultAdvisorAutoProxyCreator" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> <bean id="authorizationAttributeSourceAdvisor" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> </beans>
11、编写Shiro的Realm
Shiro通过Realm来进行认证和授权操作。在这里,我们使用JdbcRealm来与数据库进行交互。
- 1、创建JdbcRealm类
java
复制代码
package com.example.demo.shiro; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.jdbc.JdbcRealm; import org.apache.shiro.subject.PrincipalCollection; import java.util.HashSet; import java.util.Set; public class MyJdbcRealm extends JdbcRealm { @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); String password = getPasswordForUser(username); if (password == null) { throw new UnknownAccountException("No account found for user [" + username + "]"); } return new SimpleAuthenticationInfo(username, password.toCharArray(), getName()); } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); Set<String> roles = getRolesForUser(username); Set<String> permissions = getPermissionsForUser(username); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } private Set<String> getPermissionsForUser(String username) { Set<String> permissions = new HashSet<>(); // TODO: 获取该用户的所有权限,并加入到permissions集合中 return permissions; } private Set<String> getRolesForUser(String username) { Set<String> roles = new HashSet<>(); // TODO: 获取该用户的所有角色,并加入到roles集合中 return roles; } private String getPasswordForUser(String username) { // TODO: 根据用户名从数据库中获取密码 return null; } }
- 2、配置JdbcRealm 在applicationContext.xml文件中配置JdbcRealm。
xml
复制代码
<bean id="jdbcRealm" class="com.example.demo.shiro.MyJdbcRealm"> <property name="dataSource" ref="dataSource" /> <property name="authenticationQuery" value="SELECT password FROM user WHERE username = ?" /> <property name="userRolesQuery" value="SELECT role_name FROM user_role WHERE username = ?" /> <property name="permissionsQuery" value="SELECT permission FROM role_permission WHERE role_name = ?" /> <property name="saltStyle" value="COLUMN" /> </bean>
二、编写Shiro的过滤器
Shiro提供了许多过滤器,用于实现不同的功能。在这里,我们需要用到以下过滤器:
- authc:需要进行身份验证才能访问
- perms:需要具有某种权限才能访问
- anon:不需要进行身份验证就能访问
1、(bug)创建ShiroFilterFactoryBean类
在com.example.demo.shiro包下创建一个ShiroFilterFactoryBean类。
java
复制代码
package com.example.demo.shiro; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import java.util.LinkedHashMap; import java.util.Map; public class ShiroFilterFactoryBean extends ShiroFilterFactoryBean { // 配置拦截链规则 @Override protected Map<String, String> createFilterChainDefinitionMap() { Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 配置登录的url和登录成功的url filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/doLogin", "anon"); filterChainDefinitionMap.put("/logout", "logout"); // 配置不会被拦截的链接 filterChainDefinitionMap.put("/static/**", "anon"); // 配置拦截规则 filterChainDefinitionMap.put("/**", "authc"); return filterChainDefinitionMap; } // 配置登录成功之后跳转的url public void setSuccessUrl(String successUrl) { super.setSuccessUrl(successUrl); } // 配置登录页面的url public void setLoginUrl(String loginUrl) { super.setLoginUrl(loginUrl); FormAuthenticationFilter filter = (FormAuthenticationFilter) super.getFilters().get("authc"); filter.setLoginUrl(loginUrl); } }
2、配置ShiroFilterFactoryBean
xml
复制代码
<bean id="shiroFilter" class="com.example.demo.shiro.MyShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/login" /> <property name="successUrl" value="/" /> <property name="unauthorizedUrl" value="/unauthorized" /> <property name="filterChainDefinitions"> <value> /login = anon /logout = logout /admin/** = authc,perms[admin:manage] /** = authc </value> </property> </bean>
三、配置Spring MVC
在Spring MVC中,需要配置一个拦截器,用于在每个请求中进行身份验证和授权操作。
1、创建ShiroInterceptor类
在com.example.demo.shiro包下创建一个ShiroInterceptor类。
java
复制代码
package com.example.demo.shiro; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ShiroInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestUri = request.getRequestURI(); if (requestUri.equals("/login") || requestUri.equals("/doLogin")) { return true; } Subject subject = SecurityUtils.getSubject(); if (!subject.isAuthenticated()) { response.sendRedirect("/login"); return false; } String permission = getPermission(requestUri); if (!subject.isPermitted(permission)) { response.sendRedirect("/unauthorized"); return false; } return true; } private String getPermission(String requestUri) { // TODO: 根据请求URI获取相应的权限字符串 return ""; } }
2、配置ShiroInterceptor
在spring-mvc.xml文件中配置ShiroInterceptor。
xml
复制代码
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="com.example.demo.shiro.ShiroInterceptor" /> </mvc:interceptor> </mvc:interceptors>
至此,SSM框架整合Shiro的配置就完成了。可以启动应用程序并尝试访问受保护的URL来测试配置是否正确。
四、使用Shiro
1、创建用户登录页面
在src/main/resources/templates目录下创建一个名为login.html的文件,用于用户登录。
html
复制代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form method="post" action="/doLogin"> <label>用户名:</label> <input type="text" name="username"> <br> <label>密码:</label> <input type="password" name="password"> <br> <input type="submit" value="登录"> </form> </body> </html>
2、创建未授权页面
在src/main/resources/templates目录下创建一个名为unauthorized.html的文件,用于在未经授权的情况下拒绝访问。
html
复制代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>未授权页面</title> </head> <body> <h1>对不起,您无权访问该页面!</h1> </body> </html>
3、创建受保护的页面
在src/main/resources/templates目录下创建一个名为admin.html的文件,用于测试受保护的页面。
html
复制代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>管理员页面</title> </head> <body> <h1>欢迎来到管理员页面!</h1> </body> </html>
4、创建Controller
在com.example.demo.controller包下创建一个名为AdminController的控制器类。
java
复制代码
package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/admin") public class AdminController { @RequestMapping("/index") public String index() { return "admin"; } }
5、测试
启动应用程序并尝试访问以下URL:
/login
:进入登录页面; /admin/index
:进入受保护的页面,需要登录和具有admin:manage权限才能访问; /unauthorized
:访问未经授权的页面。 在登录页面输入用户名和密码,可以成功登录并进入受保护的页面;在未经授权的情况下访问受保护的页面,会重定向到未授权页面。
五、自定义Realm
在前面的示例中,我们使用了IniRealm来实现身份验证和授权,这种方式非常简单,但是不太灵活。在实际应用中,我们可能需要自定义Realm来适应特定的需求。
1、创建自定义Realm
在com.example.demo.shiro包下创建一个名为CustomRealm的类,继承AuthorizingRealm类并实现其中的两个方法。
java
复制代码
package com.example.demo.shiro; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class CustomRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { throw new AuthorizationException("PrincipalCollection method argument cannot be null."); } String username = (String) getAvailablePrincipal(principals); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); if ("admin".equals(username)) { info.addRole("admin"); info.addStringPermission("admin:manage"); } return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); if (!"admin".equals(username)) { throw new UnknownAccountException("Unknown account " + username); } if (!"123456".equals(password)) { throw new IncorrectCredentialsException("Incorrect password for account " + username); } return new SimpleAuthenticationInfo(username, password, getName()); } }
上述代码中的doGetAuthenticationInfo()方法用于实现身份验证,其实现方式与前面的示例类似;doGetAuthorizationInfo()方法用于实现授权,这里根据用户名判断用户是否为管理员,如果是,则为其添加一个名为admin的角色和一个名为admin:manage的权限。
2、在Shiro中使用自定义Realm
修改ShiroConfig类中的securityManager()方法,将其中的IniRealm替换为CustomRealm。
java
复制代码
@Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(customRealm()); return securityManager; } @Bean public CustomRealm customRealm() { return new CustomRealm(); }
现在,我们已经成功创建了一个自定义的Realm并将其集成到Shiro中,可以重新启动应用程序并进行测试。
3、测试
重新启动应用程序并尝试访问以下URL:
/login
:进入登录页面; /admin/index
:进入受保护的页面,需要登录和具有admin:manage权限才能访问; /unauthorized
:访问未经授权的页面。 在登录页面输入用户名和密码,可以成功登录并进入受保护的页面;在未经授权的情况下访问受保护的页面,会重定向到未授权页面。
六、结语
本文介绍了如何将Shiro集成到SSM框架中,并通过一个简单的示例演示了Shiro的身份验证和授权功能,以及如何自定义Realm来实现特定的需求。
当然,Shiro的功能远不止于此,它还提供了许多其他的功能和特性,如Session管理、RememberMe功能、加密和解密、过滤器等,读者可以参考官方文档深入了解。同时,由于Shiro的灵活性和可扩展性,也可以通过扩展其他组件,如Cache、Realms、SessionDAO等,来满足更多的需求。
在实际开发中,安全性通常是不容忽视的一个问题,Shiro作为一个功能丰富、易于使用、灵活可扩展的安全框架,在保护应用程序方面具有重要作用。