SSM中shiro的基本使用
shiro
用以网站的授权和认证
配置:
一、shiro基本配置文件
所用的entity user和role 实体类
1 @Entity 2 @Table(name="USER_P") 3 @DynamicInsert(value=true) 4 @DynamicUpdate(value=true) 5 public class User extends BaseEntity { 6 @Id 7 @Column(name="USER_ID") 8 @GeneratedValue(generator="system-assigned") 9 @GenericGenerator(name="system-assigned",strategy="assigned") 10 private String id; 11 12 @JsonManagedReference 13 //@ManyToOne(cascade= {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},fetch=FetchType.EAGER) 14 @ManyToOne 15 @JoinColumn(name="DEPT_ID") 16 private Dept dept; 17 18 @OneToOne(cascade=CascadeType.ALL) 19 //@OneToOne 20 @JoinColumn(name="USER_ID") 21 private Userinfo userinfo; 22 23 @JsonBackReference 24 @ManyToMany(cascade= {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},fetch=FetchType.EAGER) 25 //@ManyToMany 26 @JoinTable(name="ROLE_USER_P",joinColumns= {@JoinColumn(name="USER_ID",referencedColumnName="USER_ID")}, 27 inverseJoinColumns= {@JoinColumn(name="ROLE_ID",referencedColumnName="ROLE_ID")}) 28 @OrderBy("ORDER_NO") 29 private Set<Role> roles= new HashSet<>(); //用户对应角色 30 31 @Column(name="USER_NAME") 32 private String userName; 33 34 @Column(name="PASSWORD") 35 private String password; 36 37 @Column(name="STATE") 38 private Integer state; 39 40 //getter和setter方法 41 } 42 43 @Entity 44 @Table(name="ROLE_P") 45 @DynamicInsert(true) 46 @DynamicUpdate(true) 47 public class Role extends BaseEntity { 48 @Id 49 @Column(name="ROLE_ID") 50 @GeneratedValue(generator="system-uuid") 51 @GenericGenerator(name="system-uuid",strategy="org.hibernate.id.UUIDGenerator") 52 private String id; //角色ID 53 54 @JsonBackReference 55 @ManyToMany(cascade= {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},fetch=FetchType.EAGER) 56 @JoinTable(name="ROLE_USER_P",joinColumns= {@JoinColumn(name="ROLE_ID",referencedColumnName="ROLE_ID")}, 57 inverseJoinColumns= {@JoinColumn(name="USER_ID",referencedColumnName="USER_ID")}) 58 private Set<User> users = new HashSet<>(0); //用户对应角色 59 60 @Column(name="NAME") 61 private String name; //角色名称 62 63 @Column(name="REMARK") 64 private String remark; //备注 65 66 @Column(name="ORDER_NO") 67 private Integer orderNo; //排序号 68 69 //getter和setter方法 70 }
一个新的xml文件 beans-shiro.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <!-- 配置Spring整合shiro --> <!-- 配置安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- 自定义realm域对象 --> <property name="realm" ref="authRealm" /> </bean> <!-- 编写realm类 --> <bean id="authRealm" class="cn.ssm.trading.shiro.AuthRealm" /> <!-- Spring框架整合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="/index.jsp" /> --> <!-- 无权限跳转页面 --> <property name="unauthorizedUrl" value="/html/unauthorized.jsp" /> <!-- 定义访问规则 --> <property name="filterChainDefinitions"> <value> <!-- anon:不用认证, authc:需认证 --> /login.jsp = anon /login* = anon /logout* = anon /css/** = anon /img/** = anon /js/** = anon /images/** = anon /js/** = anon /json/** = anon /make/** = anon /skin/** = anon /static/** = anon /resource/** = anon /html/** = authc /** = authc /*.* = authc </value> </property> </bean> </beans>
在spring配置文件中(配置了aop、事务管理、数据源的那个文件)加上:
<!-- 导入shiro配置文件 -->
<import resource="classpath:beans-shiro.xml"/>
<!-- 产生shiro核心控制器的方式,使用cglib生成代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
二、shiro过滤器 配置在web.xml中 放在springmvc分发器前
<!-- Shiro核心控制器,表示由spring管理生命周期 --> <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>/*</url-pattern> </filter-mapping>
三、开启注解
在springmvc的配置文件中(配置了视图解析器的那个文件)加入:
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- 生成代理,通过代理进行控制 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <!-- 安全管理器 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> <!-- 异常处理(无权限) --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.UnauthorizedException"> /unauthorized.jsp </prop> <prop key="org.apache.shiro.authz.UnauthenticatedException"> redirect:/login.jsp </prop> </props> </property> <property name="defaultErrorView" value="/error.jsp" /> <property name="exceptionAttribute" value="ex" /> </bean>
四、认证 授权方法 编写AuthRealm类(即'域' )
1 public class AuthRealm extends AuthorizingRealm{
2 3 @Resource 4 UserService userService; 5 6 @Override 7 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) { 8 System.out.println("授权方法"); 9 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 10 User user = (User) arg0.getPrimaryPrincipal(); //获得当前登陆的用户 11 Set<Role> roles = user.getRoles(); //当前用户拥有的角色,根据自己的entity 12 //指示当前用户能访问的资源 13 for(Role role : roles) { 14 info.addStringPermission(role.getName()); 15 } 16 return info; 17 } 18 19 @Override 20 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException { 21 System.out.println("认证方法"); 22 UsernamePasswordToken token =(UsernamePasswordToken)arg0; 23 final String username = token.getUsername(); 24
//fibd的查询条件 25 Specification<User> spec = new Specification<User>() { 26 @Override 27 public Predicate toPredicate(Root<User> arg0, CriteriaQuery<?> arg1, CriteriaBuilder arg2) { 28 // TODO 自动生成的方法存根 29 return arg2.equal(arg0.get("userName").as(String.class), username); 30 } 31 }; 32 List<User> userList = userService.find(spec); //jpa,即在数据中找到满足条件的用户 33 if(userList!=null&&userList.size()>0) { 34 User user = userList.get(0); 35 //参数1:登陆的用户,参数2:密码,参数3:区分realm 36 return new SimpleAuthenticationInfo(user,user.getPassword(),getName()); 37 } 38 39 return null; 40 } 41 }
五、登陆认证方法(在controller中)
1 @RequestMapping("/security/login.action") 2 public String login(String username,String password) { 9 Subject subject = SecurityUtils.getSubject(); 10 UsernamePasswordToken token = new UsernamePasswordToken(username,password); //新建令牌 11 try { 12 subject.login(token); //会去调用认证方法16 return "redirect:/index.jsp"; 17 }catch(Exception e) {19 return "redirect:/login.jsp"; //认证失败会抛出异常 20 } 21 }
六、授权
1、使用标签
现在页面中引入shiro标签 <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>
例如:<shiro:hasPermission name='权限名'> 有该权限这里的内容才会显示 </shiro:hasPermission>
其中name属性:由于我们在上面的授权方法中加入当前用户所拥有的权限了 “info.addStringPermission(role.getName());”,所以此时会去判断name所写的权限名,当前用户是否拥有;
更多标签请自行查阅文档;
2、使用注解
在controller相应的方法上加上
1 @RequestMapping("/list.action") 2 @RequiresPermissions("权限名") 3 public String list(Model model) { 4 .... 5 }
当访问该方法时,会去判断当前用户是否拥有该权限;
若无则抛出异常,会被上面spring-mvc配置文件中所写的“异常处理”类拦截,然后转向相应页面。