spring整合shiro(含MD5加密)

shiro簡(jiǎn)介:

shiro是apache提供的一個(gè)強(qiáng)大易用的Java安全框架,用于身份驗(yàn)證望众、授權(quán)万栅、密碼學(xué)和會(huì)話管理佑钾。點(diǎn)下載源碼。

開(kāi)發(fā)環(huán)境及技術(shù):

1烦粒、mysql - 5.7.21
2休溶、navicat(mysql客戶端管理工具)
3、eclipse
4扰她、jdk9
5兽掰、tomcat 8.5
6、spring & springmvc
7徒役、mybatis 3
8孽尽、shiro
9、maven

現(xiàn)在直接開(kāi)始建項(xiàng)目忧勿,從項(xiàng)目中具體講解shiro的使用杉女,項(xiàng)目雖簡(jiǎn)單瞻讽,卻五臟俱全。


歡迎大家關(guān)注我的公眾號(hào) javawebkf熏挎,目前正在慢慢地將簡(jiǎn)書(shū)文章搬到公眾號(hào)速勇,以后簡(jiǎn)書(shū)和公眾號(hào)文章將同步更新,且簡(jiǎn)書(shū)上的付費(fèi)文章在公眾號(hào)上將免費(fèi)坎拐。


一烦磁、數(shù)據(jù)庫(kù)設(shè)計(jì):

數(shù)據(jù)庫(kù)有三張表,分別是tb_user用戶表哼勇,tb_role角色表都伪,tb_permission權(quán)限表。

1猴蹂、tb_user

圖片發(fā)自簡(jiǎn)書(shū)App

設(shè)置外鍵rid關(guān)聯(lián)tb_role表


圖片發(fā)自簡(jiǎn)書(shū)App

2院溺、tb_role

圖片發(fā)自簡(jiǎn)書(shū)App

3、tb_permission

圖片發(fā)自簡(jiǎn)書(shū)App

設(shè)置外鍵關(guān)聯(lián)tb_role表


圖片發(fā)自簡(jiǎn)書(shū)App

二磅轻、項(xiàng)目環(huán)境搭建:

1珍逸、新建maven web app,結(jié)構(gòu)如下:

圖片發(fā)自簡(jiǎn)書(shū)App

2聋溜、接下來(lái)就是添加依賴:

<dependencies>

    <!-- junit測(cè)試 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

    <!-- 添加Servlet支持 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.1</version>
    </dependency>

    <!-- 添加jtl支持 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <!-- 添加Spring支持 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.3.14.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2</version>
    </dependency>

    <!-- mybatis依賴 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.3.0</version>
    </dependency>


    <!-- 添加日志支持 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.12</version>
    </dependency>
    
    <!-- 數(shù)據(jù)庫(kù)驅(qū)動(dòng) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.37</version>
    </dependency>
    
    <!-- c3p0數(shù)據(jù)源 -->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>


    <!-- shiro相關(guān) -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.4</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>1.2.4</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.2.4</version>
    </dependency>

</dependencies>

依賴對(duì)應(yīng)的作用在代碼中有簡(jiǎn)要的注釋谆膳。

3、完成配置文件:

在spring文件夾下有:
spring-dao.xml撮躁,
spring-mvc.xml漱病,
spring-service.xml,
spring-shiro.xml

①spring-dao.xml

<!-- 配置整合mybatis過(guò)程 -->
 <!-- 1把曼、配置數(shù)據(jù)庫(kù)相關(guān)參數(shù)properties的屬性:${url} -->
 <context:property-placeholder
     location="classpath:jdbc.properties" />

 <!-- 2杨帽、配置數(shù)據(jù)庫(kù)連接池 -->
 <bean id="dataSource"
     class="com.mchange.v2.c3p0.ComboPooledDataSource">
     <!-- 配置連接池屬性 -->
     <property name="driverClass" value="${jdbc.driver}" />
     <property name="jdbcUrl" value="${jdbc.url}" />
     <property name="user" value="${jdbc.username}" />
     <property name="password" value="${jdbc.password}" />

     <!-- c3p0連接池的私有屬性 -->
     <property name="maxPoolSize" value="30" />
     <property name="minPoolSize" value="10" />
     <!-- 關(guān)閉連接不自動(dòng)commit -->
     <property name="autoCommitOnClose" value="false" />
     <!-- 獲取連接超時(shí)時(shí)間 -->
     <property name="checkoutTimeout" value="10000" />
     <!-- 當(dāng)獲取連接失敗時(shí)重試次數(shù) -->
     <property name="acquireRetryAttempts" value="2" />
 </bean>
 
 
 <!-- 3、配置mybatis的sqlSessionFactory -->
 <bean id="sqlSessionFactory"
     class="org.mybatis.spring.SqlSessionFactoryBean">
     <property name="dataSource" ref="dataSource" />
     <!-- 自動(dòng)掃描mappers.xml文件 -->
     <property name="mapperLocations"
         value="classpath:mappers/*.xml" />
     <!-- mybatis配置文件 -->
     <property name="configLocation"
         value="classpath:mybatis-config.xml" />
 </bean>

 <!-- 4嗤军、DAO接口所在包名注盈,Spring會(huì)自動(dòng)查找其下的類(lèi) -->
 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     <property name="basePackage" value="com.zhu.shiroweb.dao" />
     <property name="sqlSessionFactoryBeanName"
         value="sqlSessionFactory"></property>
 </bean>

②spring-service.xml

    <!-- 自動(dòng)掃描 -->
    <context:component-scan base-package="com.zhu.shiroweb.service" />

③spring-mvc.xml

 <!-- 配置springmvc -->
    <!-- 1、開(kāi)啟springMvc注解模式 -->
    <mvc:annotation-driven />
    
    <!-- 2叙赚、視圖解析器 -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/" />
        <property name="suffix" value=".jsp"></property>
    </bean>
        
    <!-- 3老客、開(kāi)啟Shiro注解 -->
    <bean
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor" />
    <bean
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>
                 
    <!-- 4、掃描web相關(guān)的bean -->
    <context:component-scan base-package="com.zhu.shiroweb.controller"/>

注意:開(kāi)啟shiro注解的配置要寫(xiě)在spring-mvc.xml中震叮,具體原因我也不太清楚胧砰,有知道的大佬還請(qǐng)留言指教哦!

④spring-shiro.xml

<!-- 1苇瓣、將自定義Realm加入IOC容器 -->
    <bean id="myRealm" class="com.zhu.shiroweb.realm.MyRealm">
        
        <!-- 配置MD5加密尉间,若不進(jìn)行MD5加密,這段代碼不用 -->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!-- MD5加密 -->
                <property name="hashAlgorithmName" value="MD5"/>
                <!-- 加密次數(shù) -->
                <property name="hashIterations" value="1024"/>
            </bean>
        </property> 
        <!-- 配置MD5加密,若不進(jìn)行MD5加密乌妒,這段代碼不用 -->
        
    </bean>  
    
    <!-- 2汹想、配置安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
      <property name="realm" ref="myRealm"/>  
    </bean>  
    
    <!-- 3、配置Shiro過(guò)濾器撤蚊,id名必須和web.xml中的過(guò)濾器名一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全接口,這個(gè)屬性是必須的 -->  
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份認(rèn)證失敗古掏,則跳轉(zhuǎn)到登錄頁(yè)面的配置 -->  
        <property name="loginUrl" value="/login.jsp"/>
        <!-- 權(quán)限認(rèn)證失敗,則跳轉(zhuǎn)到指定頁(yè)面 -->  
        <property name="unauthorizedUrl" value="/unauthor.jsp"/>  
        <!-- Shiro連接約束配置,即過(guò)濾鏈的定義 -->  
        <property name="filterChainDefinitions">  
            <value>  
                /login=anon
                /admin/**=authc,roles[admin]
            </value>  
        </property>
    </bean>  
    
    <!-- 4侦啸、保證實(shí)現(xiàn)了Shiro內(nèi)部lifecycle函數(shù)的bean執(zhí)行 -->  
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

以下配置文件在resources根目錄:
⑤jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///#?useUnicode=true&characterEncoding=utf8
jdbc.username=#
jdbc.password=#

⑥log4j.properties

log4j.rootLogger=DEBUG, Console  
  
#Console  
log4j.appender.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.layout=org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n  
  
log4j.logger.java.sql.ResultSet=INFO  
log4j.logger.org.apache=INFO  
log4j.logger.java.sql.Connection=DEBUG  
log4j.logger.java.sql.Statement=DEBUG  
log4j.logger.java.sql.PreparedStatement=DEBUG  

⑦mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 別名 -->
    <typeAliases>
        <package name="com.zhu.shiroweb.entity"/>
    </typeAliases>
</configuration>

web.xml在WEB-INF目錄下:
⑧web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1" metadata-complete="true">
    <display-name>shiroweb</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- Spring配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-*.xml</param-value>
    </context-param>
    
    <!-- 添加對(duì)springmvc的支持 -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- Spring監(jiān)聽(tīng)器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    
    <!-- shiro過(guò)濾器定義 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <!-- 該值缺省為false,表示生命周期由SpringApplicationContext管理,設(shè)置為true則表示由ServletContainer管理 -->
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- 編碼過(guò)濾器,非必須 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <async-supported>true</async-supported>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

至此已完成所有配置槽唾,所有的配置文件核心代碼都寫(xiě)了注釋。

三光涂、項(xiàng)目功能實(shí)現(xiàn)

登錄驗(yàn)證:

項(xiàng)目功能描述:
在數(shù)據(jù)庫(kù)中有兩個(gè)用戶庞萍,一個(gè)tom,角色為admin忘闻,對(duì)應(yīng)的權(quán)限有create,delete,query和update钝计,另一個(gè)用戶cat,角色為guest齐佳,權(quán)限只有create和query私恬。

1、首先新建User實(shí)體類(lèi)(set炼吴、get方法略):
User.java

public class User {
    private Integer uid;
    private String userName;
    private String password;
}

2本鸣、dao層的開(kāi)發(fā)
UserDao.java

public interface UserDao {
    
    /**
     * 根據(jù)用戶名查詢用戶
     * @param userName
     * @return
     */
    public User getByUserName(String userName);
    
    /**
     * 根據(jù)用戶名查詢角色
     * @param userName
     * @return
     */
    public Set<String> getRoles(String userName);
    
    /**
     * 根據(jù)用戶名查詢權(quán)限
     * @param userName
     * @return
     */
    public Set<String> getPermissions(String userName);

}

UserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhu.shiroweb.dao.UserDao">

    <resultMap type="com.zhu.shiroweb.entity.User" id="UserResult">
        <result property="uid" column="uid"/>
        <result property="userName" column="user_name"/>
        <result property="password" column="pass_word"/>
    </resultMap>
    
    <select id="getByUserName" parameterType="String" resultMap="UserResult">
        select * 
        from tb_user 
        where user_name=#{userName}
    </select>
    
    <select id="getRoles" parameterType="String" resultType="String">
        select r.role_name
        from tb_user u,tb_role r 
        where u.rid=r.rid 
        and u.user_name=#{userName}
    </select>
    
    <select id="getPermissions" parameterType="String" resultType="String">
        select p.permission_name 
        from tb_user u,tb_role r,tb_permission p 
        where u.rid=r.rid 
        and p.rid=r.rid 
        and u.user_name=#{userName}
    </select>

</mapper> 

注意:這里并沒(méi)有role和permission對(duì)應(yīng)的實(shí)體類(lèi),也可以新建其對(duì)應(yīng)的實(shí)體類(lèi)硅蹦,然后把他們?cè)O(shè)置為User的成員變量荣德,用List集合裝載。但是這樣做更麻煩一點(diǎn)童芹,因?yàn)榈认聅hiro要用到的就是Set集合涮瞻,如果是List等下還需做轉(zhuǎn)換。

3假褪、dao層測(cè)試
寫(xiě)到這可以做一下junit測(cè)試饲宛,由于篇幅原因,此處不再贅述嗜价。

4、service層開(kāi)發(fā)
由于并沒(méi)有增加邏輯幕庐,只是簡(jiǎn)單調(diào)用dao層久锥,所以不再說(shuō)明。

5异剥、自定義realm
MyRealm.java

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 為登錄用戶授予權(quán)限和角色
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.getRoles(userName));
        authorizationInfo.setStringPermissions(userService.getPermissions(userName));
        return authorizationInfo;
    }

    /**
     * 驗(yàn)證當(dāng)前登錄用戶
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName = (String) token.getPrincipal();
        User user = userService.getByUserName(userName);
        
        //使用md5加密
        //當(dāng)前realm對(duì)象的name
        String realmName = getName();
        //鹽值
        ByteSource credenttialsSalt = ByteSource.Util.bytes(user.getUserName());
        //封裝用戶信息瑟由,構(gòu)建AuthenticationInfo對(duì)象并返回
        AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(),
                credenttialsSalt, realmName);
        return authcInfo;
        //使用md5加密
        

        //不加密
        /*
         * if (user != null) { 
         *     AuthenticationInfo authcInfo = new
         *            SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), "xx");
         *      return authcInfo; 
         * } else { 
         *      return null;
         * }
         */
        //不加密
    }

這個(gè)類(lèi)就驗(yàn)證登錄和為用戶授權(quán)兩個(gè)方法,代碼中已有注釋說(shuō)明冤寿。若不使用MD5加密歹苦,則把我寫(xiě)了MD5加密注釋之間那段代碼注釋掉青伤,把下面注釋放開(kāi)就行;若要使用MD5加密,數(shù)據(jù)庫(kù)中的密碼也得是加密后的密碼可以通過(guò)下面的方法獲取明文密碼對(duì)應(yīng)的密文密碼殴瘦。
獲取密文的方法:

public static void main(String[] args) {
        String hashAlgorithName = "MD5";
        String password = "5678";
        int hashIterations = 1024;
        ByteSource credentialsSalt = ByteSource.Util.bytes("cat");
        Object obj = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);
        System.out.println(obj);
    }

6狠角、用戶登錄的Controller

@Controller
@RequestMapping("/user")
public class UserController {
    
    /**
     *
     * @param user
     * @param request
     * @return
     */
    @RequestMapping("/login")
    public String login(User user,HttpServletRequest request){
        //獲取當(dāng)前登錄用戶
        Subject subject=SecurityUtils.getSubject();
        //封裝表單中提交的用戶名和密碼
        UsernamePasswordToken token=new UsernamePasswordToken(user.getUserName(), user.getPassword());
        try{
            //調(diào)用login方法,傳入封裝好的token
            subject.login(token);
            //登錄成功跳轉(zhuǎn)success.jsp
            return "redirect:/success.jsp";
        }catch(Exception e){
            e.printStackTrace();
            //登錄失敗就重新登錄
            request.setAttribute("errorMsg", "登錄失敗");
            return "login";
        }
    }
    
}

7蚪腋、login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/user/login" method="post">
    userName:<input type="text" name="userName" value="${user.userName }"/><br/>
    password:<input type="password" name="password" value="${user.password }"><br/>
    <input type="submit" value="login"/><font color="red">${errorMsg }</font>
</form>
</body>
</html>

過(guò)程梳理:
在controller中獲取到前端表單輸入的用戶名和密碼丰歌,封裝到token中,然后調(diào)用subject的login的方法屉凯,傳入這個(gè)token立帖,這個(gè)token就會(huì)把數(shù)據(jù)帶到realm中,realm中再調(diào)service層查詢悠砚,根據(jù)前端token中攜帶的用戶名去查詢數(shù)據(jù)庫(kù)中記錄晓勇,進(jìn)行密碼比對(duì)。

這里解釋spring-shiro.xml中/login=anon的作用灌旧,這行代碼的意思就是不攔截登錄方法绑咱,可以匿名訪問(wèn)。

以上就是驗(yàn)證登錄的整個(gè)流程节榜。

授權(quán):

需求描述:
1羡玛、指定角色:
AdminController只有具有admin角色(tom)才能訪問(wèn);
GuestController只有具有g(shù)uest角色(cat)才能訪問(wèn);
2、指定權(quán)限:
PermissionController只有具有create權(quán)限(tom和cat)的用戶才能訪問(wèn);
涉及知識(shí)點(diǎn):
1宗苍、在spring-shiro.xml中進(jìn)行授權(quán)驗(yàn)證
2稼稿、注解方式授權(quán)驗(yàn)證
3、jsp中授權(quán)驗(yàn)證
4讳窟、多級(jí)路由匹配規(guī)則

正式開(kāi)始:

1让歼、AdminController.java

@Controller
@RequestMapping("/admin")
public class AdminController {

    /**
     *
     * @param user
     * @param request
     * @return
     */
    @RequestMapping("/test")
    public String adminTest() {
        //Subject subject = SecurityUtils.getSubject();
        //if(subject.hasRole("admin")) {
            return "admin";
        //}else {
        //  return "login";
        //}
        
    }

}

這個(gè)授權(quán)驗(yàn)證寫(xiě)在spring-shiro.xml中:/admin/**=authc,roles[admin],這樣就表示要有admin這個(gè)角色的用戶才能訪問(wèn)丽啡。同時(shí)這個(gè)也是雙重路由谋右,/admin/**就表示攔截admin開(kāi)頭的路由。

2补箍、GuestController.java

public class GuestController {
    
    @RequiresRoles("guest")
    @RequestMapping("/guest")
    public String guestTest() {
        return "guest";
    }

}

這個(gè)是使用注解方式進(jìn)行權(quán)限驗(yàn)證的改执,@RequiresRoles("guest")就表示要有g(shù)uest這個(gè)角色才能訪問(wèn)這個(gè)路由。

3坑雅、PermissionsController.java

@Controller
public class PermissionsController {
    /**
     *
     * @param user
     * @param request
     * @return
     */
    @RequestMapping("/permissions")
    public String permissionTest(){
        Subject subject = SecurityUtils.getSubject();
        if(subject.isPermitted("create")) {
            return "permission";
        }else {
            return "login";
        }
        
    }
    
}

這個(gè)是直接在Controller中獲取到登錄用戶辈挂,然后用Subject對(duì)象的isPermitted方法就行判斷。subject.isPermitted("create")用來(lái)判斷登錄的用戶是否有create權(quán)限裹粤,有就true终蒂,沒(méi)有就是false。

4、接下來(lái)看看前端頁(yè)面:
①success.jsp
登錄成功跳轉(zhuǎn)到這個(gè)頁(yè)面

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
       歡迎你!
    <br>
    <a href="http://localhost:8080/shiroweb/admin/test">有admin角色才能訪問(wèn)</a>
    <br>

    <a href="http://localhost:8080/shiroweb/permissions">有create權(quán)限就可以訪問(wèn)</a><br>
    <a href="http://localhost:8080/shiroweb/guest">guest才能訪問(wèn)</a>

</body>
</html>

這里定義了三個(gè)鏈接拇泣,分別指向上面那三個(gè)controller噪叙。

②admin.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
  歡迎有admin角色的你!
</body>
</html>

③guest.jsp

    pageEncoding="utf-8"%>
    <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>

   <shiro:hasRole name="guest">
        歡迎guest!(只有g(shù)uest角色登錄進(jìn)來(lái)才能顯示這段話)<shiro:principal/>
    </shiro:hasRole>
    
    <shiro:hasRole name="admin">
        歡迎admin!(只有admin角色登錄進(jìn)來(lái)才能顯示這段話)<shiro:principal/>
    </shiro:hasRole>

</body>
</html>

這里就用到了jsp標(biāo)簽形式判斷角色霉翔,<shiro:hasRole name="#">xxx</shiro:hasRole>就是用來(lái)判斷當(dāng)前用戶有沒(méi)有#角色睁蕾,有#角色才會(huì)顯示xxx內(nèi)容。

注意:使用shiro的jsp標(biāo)簽要在jsp頁(yè)面中添加<%@taglibprefix="shiro"uri="http://shiro.apache.org/tags"%>

④permission.jsp

    pageEncoding="UTF-8"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
  歡迎有你早龟! <shiro:hasPermission name="delete">
     只有擁有delete權(quán)限的人登錄進(jìn)來(lái)才能顯示這段話.<shiro:principal/>
    </shiro:hasPermission>
</body>
</html>

這里用到了<shiro:hasPermissionname="#">xxx</shiro:hasPermission>來(lái)判斷權(quán)限惫霸,只有具有#權(quán)限的用戶才會(huì)顯示xxx內(nèi)容。

⑤unauthor.jsp

    pageEncoding="utf-8"%>
    <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
  對(duì)不起葱弟,你沒(méi)有操作權(quán)限!
  <a href="login.jsp">點(diǎn)此登錄</a>
</body>
</html>

權(quán)限認(rèn)證失敗時(shí)跳轉(zhuǎn)到此頁(yè)面壹店,因?yàn)樵趕pring-shiro.xml中配置過(guò)。

四芝加、項(xiàng)目測(cè)試

1硅卢、用tom登錄
分析:tom具有admin角色和所有權(quán)限,所以success.jsp頁(yè)面的前兩個(gè)鏈接可以訪問(wèn)藏杖,且permission.jsp的<shiro:hasPermission name="delete">標(biāo)簽里面的話會(huì)顯示将塑。第三個(gè)鏈接不能訪問(wèn),會(huì)拋出異常蝌麸,因?yàn)樾枰猤uest角色才能訪問(wèn)点寥。
結(jié)果:

圖片發(fā)自簡(jiǎn)書(shū)App

圖片發(fā)自簡(jiǎn)書(shū)App
圖片發(fā)自簡(jiǎn)書(shū)App
圖片發(fā)自簡(jiǎn)書(shū)App
圖片發(fā)自簡(jiǎn)書(shū)App

2、用cat登錄
分析:cat具有g(shù)uest角色和create 以及query權(quán)限来吩,所以success.jsp的第一個(gè)鏈接不能訪問(wèn)敢辩,會(huì)跳轉(zhuǎn)到unauthor.jsp,第二個(gè)鏈接可以訪問(wèn)弟疆,但是不能顯示<shiro:hasPermission name="delete">標(biāo)簽里面的話戚长,第三個(gè)鏈接可以訪問(wèn),且能顯示<shiro:hasRole name="guest">里面的話怠苔。
結(jié)果:

圖片發(fā)自簡(jiǎn)書(shū)App
圖片發(fā)自簡(jiǎn)書(shū)App
圖片發(fā)自簡(jiǎn)書(shū)App

所有結(jié)果符合預(yù)期同廉,測(cè)試通過(guò)!

五柑司、知識(shí)點(diǎn)補(bǔ)充

1迫肖、url匹配規(guī)則:

/admin?=authc

表示admin1需要認(rèn)證,admin2也需要攒驰,但是admin不一定咒程,因?yàn)閱?wèn)號(hào)表示單個(gè)字符

/admin*=authc

表示admin1需要認(rèn)證,admin21需要讼育,admin也需要,*號(hào)表示一個(gè)或多個(gè)字符

/admin/**=authc

可以匹配多路徑,比如admin/a/b

2奶段、
Subject對(duì)象除了isPermitted("#")判斷是否擁有#權(quán)限饥瓷,還有hasRole("#")判斷是否有#角色,hasRoles(Arrays.asList("role1","role2"))來(lái)判斷是否有role1和role2角色痹籍。

3呢铆、其他注釋:

@RequiresAuthentication
表示要驗(yàn)證通過(guò)才能被訪問(wèn)

@RequiresGuest
表示之前session中沒(méi)有被驗(yàn)證過(guò)才能訪問(wèn)

@RequiresPermissions("create")
表示有create權(quán)限才能訪問(wèn)

@RequiresRoles("admin")
只有admin這個(gè)角色才能訪問(wèn)

@RequiresUser
指定用戶才能訪問(wèn)

總結(jié):

shiro提供了認(rèn)證登錄,授權(quán)蹲缠,密碼加密等功能棺克,方便易用。授權(quán)可以在spring-shiro中定義過(guò)濾鏈线定,可以使用注釋?zhuān)部梢栽赾ontroller 方法中用Subject對(duì)象的方法判斷娜谊,還可以在jsp中使用標(biāo)簽。

以上內(nèi)容是個(gè)人學(xué)習(xí)筆記整理斤讥,如有錯(cuò)誤纱皆,歡迎批評(píng)指正!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芭商,一起剝皮案震驚了整個(gè)濱河市派草,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铛楣,老刑警劉巖近迁,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異簸州,居然都是意外死亡鉴竭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)勿侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拓瞪,“玉大人,你說(shuō)我怎么就攤上這事助琐〖拦。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵兵钮,是天一觀的道長(zhǎng)蛆橡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)掘譬,這世上最難降的妖魔是什么泰演? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮葱轩,結(jié)果婚禮上睦焕,老公的妹妹穿的比我還像新娘藐握。我一直安慰自己,他們只是感情好垃喊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布猾普。 她就那樣靜靜地躺著,像睡著了一般本谜。 火紅的嫁衣襯著肌膚如雪初家。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,184評(píng)論 1 308
  • 那天乌助,我揣著相機(jī)與錄音溜在,去河邊找鬼。 笑死他托,一個(gè)胖子當(dāng)著我的面吹牛掖肋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播上祈,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼培遵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了登刺?” 一聲冷哼從身側(cè)響起籽腕,我...
    開(kāi)封第一講書(shū)人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纸俭,沒(méi)想到半個(gè)月后皇耗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揍很,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年郎楼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窒悔。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呜袁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出简珠,到底是詐尸還是另有隱情阶界,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布聋庵,位于F島的核電站膘融,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏祭玉。R本人自食惡果不足惜氧映,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脱货。 院中可真熱鬧岛都,春花似錦律姨、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至多矮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哈打,已是汗流浹背塔逃。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留料仗,地道東北人湾盗。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像立轧,于是被迫代替她去往敵國(guó)和親格粪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 說(shuō)明:本文很多觀點(diǎn)和內(nèi)容來(lái)自互聯(lián)網(wǎng)以及各種資料氛改,如果侵犯了您的權(quán)益帐萎,請(qǐng)及時(shí)聯(lián)系我,我會(huì)刪除相關(guān)內(nèi)容胜卤。 權(quán)限管理 基...
    寇寇寇先森閱讀 7,601評(píng)論 8 76
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理疆导,服務(wù)發(fā)現(xiàn),斷路器葛躏,智...
    卡卡羅2017閱讀 134,695評(píng)論 18 139
  • 一澈段、架構(gòu) 要學(xué)習(xí)如何使用Shiro必須先從它的架構(gòu)談起,作為一款安全框架Shiro的設(shè)計(jì)相當(dāng)精妙舰攒。Shiro的應(yīng)用...
    ITsupuerlady閱讀 3,535評(píng)論 4 32
  • Shiro Demo 準(zhǔn)備工作 運(yùn)行前申明 請(qǐng)看完本頁(yè)面的所有細(xì)節(jié),對(duì)你掌握這個(gè)項(xiàng)目來(lái)說(shuō)很重要偶芍,別一上來(lái)就搞充择,你不...
    全是為了他閱讀 4,240評(píng)論 4 65
  • 聽(tīng)微課時(shí)聽(tīng)到一個(gè)故事椎麦,很有感觸,分享給大家材彪。 故事的主人公是一個(gè)小男孩观挎,他非常的盼望自己長(zhǎng)大琴儿,于是,經(jīng)常祈求老天爺...
    喻青閱讀 520評(píng)論 2 2