nullcy 2016-01-29
这一节说明shiro对登录模块的限制,这一节可能用到的接口有:SecurityManager,Realm,AuthenticationToken,AuthenticationInfo,PrincipalCollection,如果你对这些接口不熟悉的话,回到第一节先看看他们的大概介绍。
登录模块的大概流程很简单,用户提交用用名+密码,然后从数据库查找该用户,如果没有找到怎么样,找到了用户但是密码不对又怎么样。先将我搭建的shiro项目的pom.xml贴出,方便你的测试。在这个项目中我集成了spring+springMVC+shiro。
<properties> <spring.version>4.1.6.RELEASE</spring.version> <junit.version>4.11</junit.version> <jackson.version>2.4.2</jackson.version> <shiro.version>1.2.2</shiro.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> </dependencies>
我们在实际项目中对shiro的使用是集成在spring中使用的,不会用到官网上提到的shiro.ini,因为没有人会将权限 角色定义在一个文档中,我将spring的xml的配置和项目的web.xml的配置贴出来,以做到我们的项目是一样的。
web.xml
<web-app> <!-- needed for ContextLoaderListener --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <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>*.do</url-pattern> </filter-mapping> <!-- Bootstraps the root web application context before servlet initialization --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
spring的xml,
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <!-- override these for application-specific URLs if you like: <property name="loginUrl" value="/login.jsp"/> <property name="successUrl" value="/home.jsp"/> <property name="unauthorizedUrl" value="/unauthorized.jsp"/> --> <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean --> <!-- defined will be automatically acquired and available via its beanName in chain --> <!-- definitions, but you can perform instance overrides or name aliases here if you like: --> <!-- <property name="filters"> <util:map> <entry key="anAlias" value-ref="someFilter"/> </util:map> </property> --> <!-- <property name="filterChainDefinitions"> <value> # some example chain definitions: /admin/** = authc, roles[admin] /docs/** = authc, perms[document:read] /** = authc # more URL-to-FilterChain definitions here </value> </property> --> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- Single realm app. If you have multiple realms, use the 'realms' property instead. --> <property name="realm" ref="myRealm" /> <!-- By default the servlet container sessions will be used. Uncomment this line to use shiro's native sessions (see the JavaDoc for more): --> <!-- <property name="sessionMode" value="native"/> --> </bean> <bean id="myRealm" class="realm.MyRealm" /> </beans>
其中MyRealm,因为我们这里仅仅是做登录,没有涉及到权限验证,所以直接继承自AuthenticatingRealm即可。代码如下:
public class MyRealm extends AuthenticatingRealm{ private Map<String,String> db = new HashMap<String,String>(); { db.put("张三","aaa"); db.put("李四", "bbb"); } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { final String username = (String) token.getPrincipal(); final String password = db.get(username); if(db.get(username)==null){ throw new UnknownAccountException(); } AuthenticationInfo info = new AuthenticationInfo() { private static final long serialVersionUID = -1174132738824136785L; public PrincipalCollection getPrincipals() { SimplePrincipalCollection coll = new SimplePrincipalCollection(username,"DB");//暂时没有考虑中间修改用户名的情况 Object o = coll.getPrimaryPrincipal();//表示是从数据库中来的,这里的DB仅仅是象征意义, System.out.println(o.getClass().getName()); return coll; } public Object getCredentials() {//暂时没有考虑中间修改密码的情况。 return password; } }; return info; } }
这个是访问的controller @Controller public class ShiroControllerLogin { @ResponseBody @RequestMapping("/login.do") public String denglu(String username,String password,HttpSession session){ UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject user = SecurityUtils.getSubject(); try { user.login(token); } catch (IncorrectCredentialsException e1) { return "密码不正确"; }catch(UnknownAccountException e2){ return "用户名不存在"; } /** * 你的登陆操作假设已经完成 */ return "成功登陆"; } }
希望你也能做到跟我完全一样的代码,然后在下一节中我将尽可能多的查看shiro关于登录的源码。