1.配置web.xmlgit
<!-- 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>/actions/*</url-pattern> </filter-mapping>
2.配置shiro.xmlgithub
<!-- 這個bean的id與web.xml中shiro相關配置保持一致 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!-- 沒認證後重定向的位置 --> <property name="loginUrl" value="/login.jsp"/> <!-- 登陸成功跳轉的位置 --> <property name="successUrl" value="/home.jsp"/> <!-- 沒有權限跳轉的位置 --> <property name="unauthorizedUrl" value="/unauthorized.jsp"/> <!-- 攔截請求--> <property name="filterChainDefinitions"> <value> <!-- 登陸請求不攔截 --> /actions/security/login = anon <!-- 訪問admin相關的請求,須要認證, 且通過自定義攔截器permissionFilter,最後還須要coder權限--> /actions/admin/** = authc,permissionFilter,roles[coder] /actions/logout = logout /actions/** = authc </value> </property> <!-- 用戶自定義的過濾器 --> <property name="filters"> <map> <entry key="permissionFilter" value-ref="userAccessControlFilter"/> <!--<entry key="logout" value-ref="logoutFilter"/>--> </map> </property> </bean>
3.spring的配置文件中引入shiro.xmlweb
<!-- 導入shiro的配置文件 --> <import resource="shiro.xml"/>
4.自定義Realm和自定義攔截器spring
public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * 強制重寫的認證方法 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //還記得嗎,token封裝了客戶端的賬號密碼,由Subject拉客並最終帶到此處 String clientUsername = (String) token.getPrincipal(); //從數據庫中查詢賬號密碼 String passwordFromDB = userService.findPasswordByName(clientUsername); if (passwordFromDB == null) { //若是根據用戶輸入的用戶名,去數據庫中沒有查詢到相關的密碼 throw new UnknownAccountException(); } /** * 返回一個從數據庫中查出來的的憑證。用戶名爲clientUsername,密碼爲passwordFromDB 。封裝成當前返回值 * 接下來shiro框架作的事情就很簡單了。 * 它會拿你的輸入的token與當前返回的這個數據庫憑證SimpleAuthenticationInfo對比一下 * 看看是否是同樣,若是用戶的賬號密碼與數據庫中查出來的數據同樣,那麼本次登陸成功 * 不然就是你密碼輸入錯誤 */ return new SimpleAuthenticationInfo(clientUsername, passwordFromDB, "UserRealm"); } //受權 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String yourInputUsername = (String) principals.getPrimaryPrincipal(); //構造一個受權憑證 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //經過你的用戶名查詢數據庫,獲得你的權限信息與角色信息。並存放到權限憑證中 info.addRole(getYourRoleByUsernameFromDB(yourInputUsername)); info.addStringPermissions(getYourPermissionByUsernameFromDB(yourInputUsername)); //返回你的權限信息 return info; } private String getYourRoleByUsernameFromDB(String username) { return "coder"; } private List<String> getYourPermissionByUsernameFromDB(String username) { return Arrays.asList("code:insert", "code:update"); } }
@Component("userAccessControlFilter") public final class UserAccessControlFilter extends AccessControlFilter { private static final Logger LOGGER = LoggerFactory.getLogger(UserAccessControlFilter.class); /** * 便是否容許訪問,返回true表示容許. * 若是返回false,則進入本類的onAccessDenied方法中進行處理 */ @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object object) throws Exception { final Subject subject = SecurityUtils.getSubject(); //判斷用戶是否進行過登陸認證,若是沒通過認證則返回登陸頁 if (subject.getPrincipal() == null || !subject.isAuthenticated()) { return Boolean.FALSE; } final String requestURI = this.getPathWithinApplication(request); if (LOGGER.isDebugEnabled()) { LOGGER.debug("請求URL爲:{}", requestURI); } final String requestHeader = ((HttpServletRequest) request).getHeader("Referer"); //防盜鏈處理 if (requestHeader == null || "".equals(requestHeader)) { return Boolean.FALSE; } //此處能夠編寫用於判斷用戶是否有相關權限的代碼 //subject.hasRole("須要的角色"); //subject.isPermitted("須要的權限"); return Boolean.TRUE; } /** * 若是返回true,則繼續執行其它攔截器 * 若是返回false,則表示攔截住本次請求,且在代碼中規定處理方法爲重定向到登陸頁面 */ @Override protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { if (LOGGER.isDebugEnabled()) { LOGGER.debug("當前賬號沒有相應的權限!"); } //重定向到登陸頁面 this.redirectToLogin(servletRequest, servletResponse); return Boolean.FALSE; } }
5.login.jsp和Controller數據庫
<form action="<c:url value="/actions/security/login"/>" method="post"> 用戶名<input type="text" name="username"><br> 密碼<input type="password" name="password"><br> <input type="submit" value="提交"> </form>
@RequestMapping(value = "security/login", method = {RequestMethod.POST}) public String login(@RequestParam("username") String userName, @RequestParam("password") String password) { //獲取到Subject門面對象 Subject subject = getSubject(); try { //將用戶數據交給Shiro框架去作 //你能夠在自定義Realm中的認證方法doGetAuthenticationInfo()處打個斷點 subject.login(new UsernamePasswordToken(userName, password)); } catch (AuthenticationException exception) { if (!subject.isAuthenticated()) { //登陸失敗 return "fail"; } } //登陸成功 return "home"; } @RequestMapping(value = "admin") public String enterAdmin() { //跳轉到 web-inf/pages/admin.jsp頁面 return "admin"; }
6.index。jspapache
<a href="<c:url value="/actions/obtainAllUsers"/> ">測試超連接</a><br> <a href="<c:url value="/actions/admin"/> ">進入管理員頁面</a><br> <a href="<c:url value="/actions/logout"/> ">退出</a>
登錄成功才能訪問其餘連接,不然一致都是loginapp