shiro是什么:Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障。
shiro官方文档:http://shiro.apache.org/authentication.html。
首先在pom.xml中添加shiro依赖:
<!-- shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 添加shiro web支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 添加shiro spring支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 添加jstl支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
编写自己的Realm(当验证currentUser.login(token)时会执行此类的方法):
package com.yrok.realm;
import javax.annotation.Resource;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.yrok.entity.TUser;
import com.yrok.mapper.UserMapper;
public class MyRealm extends AuthorizingRealm {
@Resource
UserMapper userMapper;
/**
* 为当前已经登陆成功的用户授予权限和角色
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal(); // 获取用户名
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userMapper.getRoles(username)); //设置角色
authorizationInfo.setStringPermissions(userMapper.getPermissions(username)); //设置权限
return authorizationInfo;
}
/**
* 验证当前正在登录的用户,获取认证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal(); // 获取用户名
TUser tUser = userMapper.getByUsername(username);
if (tUser != null) {
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(tUser.getUsername(), tUser.getPassword(), "myrealm");
return authcInfo;
} else {
return null;
}
}
}
spring集成mybatis参考我的另一篇文章:
SSM配置模板
编写UserMapper:
package com.yrok.mapper;
import java.util.List;
import java.util.Set;
import org.apache.ibatis.annotations.Param;
import com.yrok.entity.TUser;
public interface UserMapper {
public TUser getByUsername(String username);
public Set<String> getRoles(String username);
public Set<String> getPermissions(String username);
}
编写UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.yrok.mapper.UserMapper" >
<select id="getByUsername" parameterType="String" resultType="TUser">
select * from t_user where username=#{username}
</select>
<select id="getRoles" parameterType="String" resultType="String">
select r.rolename from t_user u,t_role r where u.role_id=r.id and u.username=#{username}
</select>
<select id="getPermissions" parameterType="String" resultType="String">
select p.permissionname from t_user u,t_role r,t_permission p where u.role_id=r.id and p.role_id=r.id and u.username=#{username}
</select>
</mapper>
编写UserController:
package com.yrok.controller;
import java.io.IOException;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yrok.entity.TUser;
import com.yrok.entity.User;
import com.yrok.service.UserService;
@Controller
@RequestMapping(value="/user")
public class UserController {
@Resource
UserService userService;
//用户登录
@RequestMapping("/login")
public String login(TUser user, HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
try{
subject.login(token);//会跳到我们自定义的realm中
request.getSession().setAttribute("username", user.getUsername());
return "success";
}catch(Exception e){
e.printStackTrace();
request.getSession().setAttribute("username", user.getUsername());
request.setAttribute("error", "用户名或密码错误!");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
return null;
}
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
request.getSession().invalidate();
request.getRequestDispatcher("/login.jsp").forward(request, response);
return null;
}
@RequestMapping("/admin")
public String admin(HttpServletRequest request) {
return "success";
}
@RequestMapping("/student")
public String student(HttpServletRequest request) {
return "success";
}
@RequestMapping("/teacher")
public String teacher(HttpServletRequest request) {
return "success";
}
}
最后spring集成shiro的配置:
<!-- 自定义Realm -->
<bean id="myRealm" class="com.yrok.realm.MyRealm"/>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
<!-- Shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 身份认证失败,则跳转到登录页面的配置 -->
<property name="loginUrl" value="/login.jsp"/>
<!-- 权限认证失败,则跳转到指定页面 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!-- Shiro连接约束配置,即过滤链的定义 -->
<property name="filterChainDefinitions">
<value>
<!-- 访问login是不需要认证 -->
/login=anon
<!-- 访问user/admin开头的任意接口都需要认证 -->
/user/admin*=authc
/user/student*/**=roles[teacher]
/user/teacher*/**=perms["user:create"]
</value>
</property>
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 开启Shiro注解 -->
<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>
数据库sql:
CREATE TABLE `t_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`rolename` varchar(20) DEFAULT NULL COMMENT '角色名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户主键',
`username` varchar(20) NOT NULL COMMENT '用户名',
`password` varchar(20) NOT NULL COMMENT '密码',
`role_id` int(11) DEFAULT NULL COMMENT '外键关联role表',
PRIMARY KEY (`id`),
KEY `role_id` (`role_id`),
CONSTRAINT `t_user_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
CREATE TABLE `t_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`permissionname` varchar(50) NOT NULL COMMENT '权限名',
`role_id` int(11) DEFAULT NULL COMMENT '外键关联role',
PRIMARY KEY (`id`),
KEY `role_id` (`role_id`),
CONSTRAINT `t_permission_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
测试:
根据spring的配置文件中对shiro的url拦截配置,我们首先请求:http://localhost:8080/SSMShiro/user/admin来测试身份认证,然后会跳转到登录页面让我们登陆,登陆成功后,再次请求这个url就会进入success.jsp页面了。
再测试角色和权限认证,可以先后输入http://localhost:8080/ShiroSpring/user/student来测试角色认证,输入http://localhost:8080/SSMShiro/user/teacher来测试权限认证。通过登陆不同的用户去测试即可。
参考文档:
【Shiro】Apache Shiro架构之权限认证(Authorization)
【Shiro】Apache Shiro架构之集成web
【Shiro】Apache Shiro架构之自定义realm
【Shiro】Apache Shiro架构之实际运用(整合到Spring中)