在之前我们已经了解了Shiro的使用流程,但是我们是在配置文件配置的用户,角色,在实际应用中,我们会在数据库获取信息,下面我们介绍Shiro与Spring的整合过程
org.springframework
spring-core
5.0.5.RELEASE
org.springframework
spring-beans
5.0.5.RELEASE
org.springframework
spring-context
5.0.5.RELEASE
org.springframework
spring-jdbc
5.0.5.RELEASE
org.springframework
spring-tx
5.0.5.RELEASE
org.springframework
spring-web
5.0.5.RELEASE
org.springframework
spring-webmvc
5.0.5.RELEASE
org.springframework
spring-test
5.0.5.RELEASE
org.apache.commons
commons-lang3
3.7
contextConfigLocation
classpath:spring/spring-*.xml
org.springframework.web.context.ContextLoaderListener
DispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/spring-mvc.xml
DispatcherServlet
/
Insert title here
User Page
package com.wmx.shiro.control;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserControler {
@RequestMapping("/toUserPage")
public String toUserPage() {
return "user";
}
}
Shiro与Spring整合步骤如下:
org.apache.shiro
shiro-core
1.4.0
org.apache.shiro
shiro-spring
1.4.0
org.apache.shiro
shiro-web
1.4.0
ShiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
ShiroFilter
/*
public class ShiroDbRealm extends AuthorizingRealm {
/**
* *授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) principals.getPrimaryPrincipal();
List permissionList=new ArrayList();
permissionList.add("user:add");
permissionList.add("user:delete");
if (userName.equals("wmx")) {
permissionList.add("user:query");
}
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addStringPermissions(permissionList);
info.addRole("admin");
return info;
}
/**
* * 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1. 把 AuthenticationToken 转换为 UsernamePasswordToken
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
//2. 从 UsernamePasswordToken 中来获取 username
String username = upToken.getUsername();
//3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息.");
//4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
if("unknown".equals(username)){
throw new UnknownAccountException("用户不存在!");
}
//5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常.
if("monster".equals(username)){
throw new LockedAccountException("用户被锁定");
}
//6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
//以下信息是从数据库中获取的.
//1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象.
Object principal = username;
//2). credentials: 密码.
Object credentials = "123456";
//3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可
SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal, credentials, realmName);
info = new SimpleAuthenticationInfo(principal, credentials, super.getName());
return info;
}
}
/login = anon
/toLoginUI = anon
/** = authc
Shiro中默认的过滤器:
过滤器名称 | 过滤器类 | 描述 |
---|---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter | 匿名过滤器 |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter | 如果继续操作,需要做对应的表单验证否则不能通过 |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter | 基本http验证过滤,如果不通过,跳转屋登录页面 |
logout | org.apache.shiro.web.filter.authc.LogoutFilter | 登录退出过滤器 |
noSessionCreation | org.apache.shiro.web.filter.session.NoSessionCreationFilter | 没有session创建过滤器 |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter | 权限过滤器 |
port | org.apache.shiro.web.filter.authz.PortFilter | 端口过滤器,可以设置是否是指定端口如果不是跳转到登录页面 |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter | http方法过滤器,可以指定如post不能进行访问等 |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter | 角色过滤器,判断当前用户是否指定角色 |
ssl | org.apache.shiro.web.filter.authz.SslFilter | 请求需要通过ssl,如果不是跳转回登录页 |
user | org.apache.shiro.web.filter.authc.UserFilter | 如果访问一个已知用户,比如记住我功能,走这个过滤器 |
Url的匹配模式
Shiro的认证流程和我们
@Controller
@RequestMapping("/shiro")
public class LoginController {
@RequestMapping(value="/toLoginUI")
public String login(){
return "login";
}
@RequestMapping("/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password){
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
// 把用户名和密码封装为 UsernamePasswordToken 对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// rememberme
token.setRememberMe(true);
try {
// 执行登录.
currentUser.login(token);
} catch (AuthenticationException ae) {
//unexpected condition? error?
System.out.println("登录失败: " + ae.getMessage());
return "redirect:toLoginUI";
}
}
return "list";
}
}
Insert title here
Login Page
在view文件夹下新建list.html页面
Insert title here
List Page
如下图所示,我们访问user/toUserPage会自动定位到登录页面
输入账号:unknown 密码:随意输入提交,控制台输出
从数据库中获取 username: unknown 所对应的用户信息.
登录失败: 用户不存在!
输入账号:monster 密码随意输入,提交,控制台输出
从数据库中获取 username: monster 所对应的用户信息.
登录失败: 用户被锁定