Subject进行Shiro的授权操作,首先委托给Security Manager,在由Security Manager 委托给Authenticator,由Authenticator授权器进行真正的授权操作。
这里记录在Spring环境下配置Shiro框架。
1、加入依赖:org.apache.shiro-core ,org.apache.shiro-web,org.apache.shiro-spring 版本都为1.2.2
2、在web.xml中加入ShiroFilter代理类
shiro和spring的集成需要代理类,这个shiro过滤器会从spring的容器中寻找真正的ShiroFilter
注:filter-name必须和配置文件真实的Bean一致
<filter> <filter-name>shiroFilter</filter-name><!--shiroFilter必须和shiro配置文件(spring-shiro.xml)中真实的ShiroFilterBeanId一致--> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3、在IOC容器中配置真正的ShiroFilter,这里创建一个专门用于Shiro的配置文件
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="SecurityManager"/> <property name="loginUrl" value="/webroot/html/login.html"/> <property name="filterChainDefinitions"> <value> /webroot/js/**=anon /wxbackstage/login=anon /**=authc </value> </property>
在shiroFilter Bean的属性中,securityManager是必须的,这里依赖SecurityManager
loginUrl,没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。
successUrl :登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。
unauthorizedUrl :没有权限默认跳转的页面
filterChainDefinitions(重点):这是一个Shiro过滤链,配置哪些web的资源需要认证(Authentication)才能访问,哪些资源需要授权(Authorization)才能访问。
格式:url=过滤器
默认的过滤器:anon – org.apache.shiro.web.filter.authc.AnonymousFilter
authc – org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic – org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms – org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port – org.apache.shiro.web.filter.authz.PortFilter
rest – org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles – org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl – org.apache.shiro.web.filter.authz.SslFilter
user – org.apache.shiro.web.filter.authc.UserFilter
logout – org.apache.shiro.web.filter.authc.LogoutFilter
配置例子:
/**=anon:所有的资源匿名也可以访问
/admin/**=authc:admin下的所有网页或者请求方法都需要认证才能访问
/admin/user=roles[admin]:admin/user下的网页或者请求方法需要有admin这个角色才能访问,参数是多个必须逗号分开,加上引号,如:rolse["admin1,admin2"]
/**=rest[user]:分区请求方法,相当于/**=perms[user:method],其中,method代表,get,post,put,delete等等
/**=port[8081],请求的url端口为8081,不是的话跳转到该端口进行url访问
/admins/user/**=authcBasic:
没有参数表示httpBasic认证
/admins/user/**=ssl:
没有参数,表示安全的url请求,协议为https
/admins/user/**=user:
没有参数表示必须存在用户,当登入操作时不做检查
4、配置在Shiro配置文件中配置SecurityManager
<bean id="SecurityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="StudentRealm"></property> <!--配置多个realm 可增加数据安全性 <property name="realms" > <list> <ref bean="Realm1"/> <ref bean="Realm2"/> </list> --> </bean>
这个Security Manager依赖自定义的 realm,自定义Realm可以是一个,也可以是多个
5、配置自定义realm
<bean id="StudentRealm" class="common.Shiro.StudentRealm"> <property name="wxMemberDAO" ref="wxMemberDAOImpl"></property>
<!--加密器,不管--> <property name="credentialsMatcher" ref="credentialsMarcher"></property> </bean>
自定义的realm来自SutdentRealm,同时注入了一个wxMemberDAO接口,并引入实例,从而访问数据库。(在wxMemberDAOImpl class中加入@Repository,从而获取该类bean实例)
5、配置自定义realm
public class StudentRealm extends AuthorizingRealm { //注入DAO ,同时在spring-shiro的自定义Realm进行配置 @Setter public WxMemberDAO wxMemberDAO; private Log log = LogFactory.getLog(StudentRealm.class); public String getName() { return "StudentRealm"; } /* * @Description: 授权器,验证角色身份权限的API * @Param: principalCollection * @return: org.apache.shiro.authc.AuthenticationInfo * @Author: zhijie * @Date: 2019/2/6 */ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } /* * @Description:验证器,判断用户的登录 用户输入的账号密码封装成UserNamePasswordToken * SimpleAuthenticationInfo封装查询之后的结果 * @Param: [authenticationToken] * @return: org.apache.shiro.authc.AuthenticationInfo * @Author: zhijie * @Date: 2019/2/6 */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //通过 token获取用户名,查询数据库返回用户信息 String memberId = (String) authenticationToken.getPrincipal(); GroupMember groupMember = wxMemberDAO.login(memberId); if(groupMember == null) { log.info(memberId+"没找到帐号"); throw new AuthenticationException(); } SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(memberId,groupMember.getmemberpassword(), ByteSource.Util.bytes(memberId),getName()); return simpleAuthenticationInfo; } }
继承AuthorizingRealm,更方便的继承认证和授权两个方法,先通过@Setter注入wxMemberDAO实例,在从第四步进行真正的注入。在重点看AuthenticationInfo的doGetAuthenticationInfo的方法。
通过getPrincipal()获取username,在通过login方法获取member的对象,如果不存在,则抛出异常,否则返回一个SimpleAuthenticationInfo的对象。
这个方法的参数:用户名,密码,盐(不管),这个realm的名字。
6.从service中执行login方法。
public ConcurrentSkipListMap login(String memberid,String password) { //创建当前访问路径的主体 Subject subject = SecurityUtils.getSubject(); //判断是否已经进行认证 if(subject.isAuthenticated() == false) { //将用户名和密码封装成UserNamePasswordToken UsernamePasswordToken token = new UsernamePasswordToken(memberid,password); subject.login(token); } System.out.println(subject.isAuthenticated()); GroupMember memberDepartmentPosition = wxMemberDAO.login(memberid); concurrentSkipListMap.put("AuthorizationStatus",memberDepartmentPosition.getDepartmentposition()); return concurrentSkipListMap; }
因为已经在配置文件中配置了Security Manager,所以这里直接获取访问主体即可。判断是否已经进行了认证,最终在result中返回json的格式。