一 配置shiro的filter实现URL级别权限控制
shiro的工作流程:application code(代码)--->Subject--->SecurityManager--->Realm---->SecurityManager(底层判断)---->Suject--->application code
1.配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <!-- spring配置文件位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- spring核心监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- shiro的filter --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- struts2 过滤器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> </web-app>
2.配置application.xml
anon 未认证可以访问 authc 认证后可以访问 perms 需要特定权限才能访问 roles 需要特定角色才能访问
user 需要特定用户才能访问 port 需要特定端口才能访问 reset 根据指定 HTTP 请求访问才能访问
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <!-- 配置shiro的核心Filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 配置安全管理器 --> <property name="securityManager" ref="securityManager"/> <!-- 未认证,跳转到哪个页面 --> <property name="loginUrl" value="/login.html"/> <!-- 登录页面页面 --> <property name="successUrl" value="/index.html"/> <!-- 认证后,没有权限跳转页面 --> <property name="unauthorizedUrl" value="/unauthorized.html" /> <!-- shiro URL控制过滤器规则 --> <property name="filterChainDefinitions"> <value> /login.html* =anon /user_login.action=anon <!-- 登录时在认证前访问 --> /validatecode.jsp*=anon <!-- anon 未认证可访问.authc认证后可访问--> /css/**=anon /js/**=anon /images/**=anon /services/**=anon /**=authc </value> </property> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="bosRealm"></property> </bean> <!-- shiro的后处理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"> </bean> </beans>
3.在登录界面,form表单补全,并提交.
<form class="form-horizontal" id="loginform" name="loginform" method="post" action="user_login.action">
<a href="javascript:$(‘#loginform‘).submit();" id="loginform" name="loginform" >立即登录</a>
4.在UserAction编写login方法
package cn.itcast.bos.web.action.system; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import cn.itcast.bos.domain.system.User; import cn.itcast.bos.web.action.common.BaseAction; @Namespace("/") @Controller @ParentPackage("json-default") @Scope("prototype") public class UserAction extends BaseAction<User>{ @Action(value="user_login",results={@Result(type="redirect",name="success",location="index.html") ,@Result(name="login",type="redirect",location="login.html")}) public String login(){ //用户名和密码都保存在model中 //基于shiro实现登录 Subject subject = SecurityUtils.getSubject(); //用户名和密码保存到token中 AuthenticationToken token= new UsernamePasswordToken(model.getUsername(),model.getPassword()); try { //如果正常登录,表示没有异常.登陆成功 subject.login(token); return SUCCESS; } catch (Exception e) { //如果异常,表示登录失败,重新跳转到登录页面 e.printStackTrace(); return LOGIN; } } }
5.定义Realm,实现认证方法.
package cn.itcast.bos.realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.stereotype.Component; import cn.itcast.bos.domain.system.User; import cn.itcast.bos.service.system.UserService; //加入Spring管理的注解,bean管理. @Component("bosRealm") public class BosRealm extends AuthorizingRealm{ private UserService userService ; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) { System.out.println("授权..."); return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("认证..."); //转换token UsernamePasswordToken UsernamePasswordToken=(UsernamePasswordToken) token; //根据用户名查询用户信息 User user = userService.findByUsername(UsernamePasswordToken.getUsername()); if(user==null){ //用户名不存在 //参数一:期望登陆后保存在subject中的信息 //参数二:密码 //参数三:realm的名称 //return new SimpleAuthenticationInfo(user,null,getName()); return null; }else{ //用户名存在 //当返回密码时,securityManager安全管理器会自动比较与用户传过来的密码 //如果一致,登陆成功,如果不一致,报密码错误异常 return new SimpleAuthenticationInfo(user,user.getPassword(),getName()); } } }
6.调用service与dao
package cn.itcast.bos.service.system; import cn.itcast.bos.domain.system.User; public interface UserService { public User findByUsername(String username); }
package cn.itcast.bos.service.system.impl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import cn.itcast.bos.dao.system.UserRepository; import cn.itcast.bos.domain.system.User; import cn.itcast.bos.service.system.UserService; @Service @Transactional public class UserServiceImpl implements UserService { private UserRepository userRepository ; @Override public User findByUsername(String username) { return userRepository.findByUsername(username); } }
package cn.itcast.bos.dao.system; import org.springframework.data.jpa.repository.JpaRepository; import cn.itcast.bos.domain.system.User; public interface UserRepository extends JpaRepository<User, Integer>{ public User findByUsername(String username); }
org.apache.shiro.authc.UnknownAccountException 当认证方法直接返回 null,说明用户名不存在
org.apache.shiro.authc.IncorrectCredentialsException 当返回对象中密码与用户输入密码不一致 密码错误