Shiro -- (九) 集成SSM框架

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

 

 

 

 

 

 


https://github.com/1017020555/SSM-Shiro.git框架

相關文章
相關標籤/搜索