前提:你已经创建了一个基于ssm的web项目,并配置好了相关文件,项目能正常运行。
1.引入核心依赖
<!--shiro的依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.0</version>
</dependency>
2.在spring.xml配置文件新增以下配置
<!--SecurityManager-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"></property>
</bean>
<!--创建realm对象-->
<bean id="myRealm" class="com.zjh.realm.MyRealm">
<!--设置密码加密器-->
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<!--密码加密器对象-->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="5"/>
</bean>
<!--shiro代理过滤器 id的值必须和web.xml中过滤器的名称一致-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!--未登录时跳转的路径-->
<property name="loginUrl" value="/unLogin"/>
<!--配置拦截规则-->
<property name="filterChainDefinitions">
<!--路径资源=anon authc-->
<value>
/login=anon
/login.jsp=anon
/**=authc
</value>
</property>
</bean>
3.在web.xml文件中新增以下配置
<!--shiro的过滤器 filter-name必须和shiroFilterFactoryBean的id值一样-->
<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>
注意:在配置的DispatcherServlet中一定要修改为tomcat启动时加载该类,否则,项目每次重新启动没有错误,但是重新部署会报错。
3.编写realm类
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//这里根据你自己查询的实体类可以进行修改
User user = (User) principals.getPrimaryPrincipal();
//根据id查询该用户具有的权限
List<Permission> permissions = permissionService.selectByUserId(user.getUserid());
if (permissions.size() > 0) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List<String> list = permissions.stream().map(item -> item.getPercode()).collect(Collectors.toList());
info.addStringPermissions(list);
return info;
}
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取输入账号的名称
Object username = token.getPrincipal();
//调用UserService中根据名称查询用户信息
User user = userService.selectByName(username);
//判断user是否为null
if (user != null) {
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(), salt, this.getName());
return info;
}
return null;
}
}
4.后端使用权限限制注解
@GetMapping("list")
//@RequiresPermissions(value = {"user:query", "user:delete"}, logical = Logical.OR)
//value的值为,该方法想要实现的权限
@RequiresPermissions(value = "user:query")
public String list() {
return "user: list";
}
要想让该注解生效,还需要在spring配置文件中加入
<!-- 启动Shrio的注解 shiro加在controller应该属于springmvc的配置 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<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>
5.加一个全局异常类,用来处理权限不足时的异常。
@RestControllerAdvice
public class MyGlobalException {
@ExceptionHandler(value = UnauthorizedException.class)
public Res exception01(UnauthorizedException e) {
return new Res(401, "权限不足", null);
}
}
6.未登录访问其他资源
第一种: 未登录跳转到controller接口
@RestController
public class LonginController {
@PostMapping("/login")
public Res login(String username, String userpwd) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, userpwd);
try {
subject.login(token);
return new Res(200, "登录成功", null);
} catch (Exception e) {
return new Res(500, "登录失败", null);
}
}
@GetMapping("/unLogin")
public Res unLogin() {
return new Res(402, "未登录", null);
}
}
第二种: 自定义登录过滤器
public class LoginVerifyFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("json/application;charset=utf-8");
PrintWriter writer = response.getWriter();
Res res = new Res(402, "未登录2", null);
String s = JSON.toJSONString(res);
writer.println(s);
writer.flush();
writer.close();
return false;
}
}