也是为了自己以后方便记忆,自己看了很久怎么用Shiro去做用户认证以及权限校验,特此把这个过程记录下来。也搜索很多教程都觉得讲的云里雾里,其实最后很大的帮助还是官方文档。或许是博主比较笨,废话不说直接写流程。也不知道对不对,如有不对还希望高人指点一下。
http://shiro.apache.org/spring.html :这个地址是官方整合spring的一个教程,好像只有配置文件,但是我没找到具体代 码, 具 体例子。所以也不明白。
我写的这个教程建立在你知道了Shiro一些概念,以及一些主要对象的基础上的。
第一步:先说一下Shiro的认证流程吧。这是在网上看的一个视频中讲的,自我感觉讲的很好,因为没有视频中的源码就截了个图
其实这个流程可以帮助我们明白Shiro认证的一些过程,下面开始
1,引入Shrio的相关包以及整合spring的包:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.5</version>
</dependency>
2,在web.xml文件中配置Shiro过滤器,
<!-- 添加shiro过滤器 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<!-- 该值缺省为false,表示声明周期由SpringApplicationContext管理,设置为true表示
ServletContainer管理 -->
<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>
3,但是Shiro过滤器又是由Spring容器来管理的,所以我们要在Spring容器中配置一个Shiro过滤器的bean。但是呢其实在Spring配置的是一个工厂bean对象,但是这个工厂bean对象中有很多属性可以设置。其中有个过滤器链,在这个过滤器链中就可以设置对项目资源的权限控制。其中还有个属性是<property name="securityManager" ref="securityManager"/>,这个叫做安全管理器,也是需要我们在Spring容器中去配置的。但是呢在securityManager对象中看到需要注入一个<property name="realm" ref="myRelam"/>,这个是需要我们自己去定义一个类,在下一步中会写。还有一点是<property name="unauthorizedUrl" value="/refused.jsp" />这个属性,说是当没有权限时会自动跳转到这个页面,但是我配置了之后没作用,所以就先注释掉。对于 <property name="loginUrl" value="/index.jsp" />这个属性就不用解释了吧,就是你没有认证成功,就会跳转到这个页面。对于过滤器链中的配置是什么意思应该在初步学习Shiro的认证和授权时就应该就已经知道了。
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRelam"/>
</bean>
<!-- shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 身份认证失败,则跳转到登录页面的配置 -->
<property name="loginUrl" value="/index.jsp" />
<!-- 权限认证失败,则跳转到指定页面, -->
<!--<property name="unauthorizedUrl" value="/refused.jsp" /> -->
<!-- Shiro连接约束配置,即过滤链的定义 authc -->
<property name="filterChainDefinitions">
<value>
/user/login=anon
/static/**=anon
/index.jsp=anon
/refused.jsp=anon
/**=authc
</value>
</property>
</bean>
4,自定义一个realm继承AuthorizingRealm类。(个人理解这个realm就可以干认证和授权的事)里面的代码先不管什么意思
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//这个方法是用来授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User)principalCollection.getPrimaryPrincipal();
List<String> userPermissions = userService.findUserPermissions(user.getId());
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addStringPermissions(userPermissions);
log.debug("从数据库中查询");
return authorizationInfo;
}
//这个方法是用来认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
User user = userService.getUserByName(username);
if (user == null){
throw new UnknownAccountException("账户不存在");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),getName());
return info;
}
}
4,接下来就可以写认证的Controller了。在controller中不多解释,最重要的就是当执行subject.login(usernamePasswordToken);这个方法的时候,就会执行我们自定义的realm中的认证方法。至于里面是怎么认证的我自己也不是非常的清楚,可以参考一开始的认证流程。如果前端传来的账号密码不匹配,在realm中就会抛出一个异常,然后在controller中捕捉到异常就会提示认证失败,并且还是在inde页面。如果认证成功了,就会执行redirect:/admin/main.jsp 这个转发到系统的首页。到这里用Shiro做认证就算完成了。
@Controller
@RequestMapping("/user")
public class UserAdminController {
private static final Logger log = Logger.getLogger(UserAdminController.class);// 日志文
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(User user, Model model) {
Subject subject = SecurityUtils.getSubject();
/* if (user == null){ return "login";}*///前端已经设置了账号密码不为空
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(),user.getPassword());
try {
subject.login(usernamePasswordToken);
} catch (AuthenticationException e) {
e.printStackTrace();
model.addAttribute("msg","账号或密码错误");
log.info("==============================认证失败");
return "index";
}
log.info("=================================认证成功");
return "redirect:/admin/main.jsp";
}
5,我看到视频上在Controller中是直接判断是否有异常,然后前端页面表单的name值好像也有一些规定。但是我在网上找到有例子是这样写的。所以我就这样做了。如有不对,还希望高人来指点。