shiro可以跟springMVC很好的集成。
但是对于shiro集成struts2的资料比较少。
容易遇到注解失效等问题。
因为很多老的项目可能用的是Spring+ sturts框架。
如果我们使用shiro跟sturts集成的话 需要用到sturts的注解。
这样其实struts也失去了它跳转配置的便利。
所以 考虑了之后 还是觉得 使用springMVC框架与shiro集成。
我现在有一个spirngMVC的框架,在此基础上进行shiro的添加测试。
用户分为两种用户normal,manager,有五个模块:结果查看模块,用户数据生成单选模块,用户数据生成批量模块,用户权限管理模块,操作日志查看模块。
normal用户:
结果查看模块resultlist,
用户数据生成单选模块parseResultUserlist,parseResultAdd,
用户数据生成批量模块parseResultUserlistMulti,parseResultAddMulti
manager用户:
结果查看模块resultlist,
用户数据生成单选模块parseResultUserlist,parseResultAdd,
用户数据生成批量模块parseResultUserlistMulti,parseResultAddMulti,
用户权限管理模块usermanage,
操作日志查看模块。loglist
根据shiro的模型 我们需要给User加上角色role和权限permission。因为我用的mongodb数据库是非关系型的数据库。我们把role和permission直接加在User对象里。
User.java
package com.test.domain.entity;
import java.util.List;
public class User {
private String id;
private String username;
private String password;
private List permissionList;//一个角色对应多个权限
private List roleList;//一个用户具有多个角色
private List otherContacts;// 其他联系人
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List getPermissionList() {
return permissionList;
}
public void setPermissionList(List permissionList) {
this.permissionList = permissionList;
}
public List getRoleList() {
return roleList;
}
public void setRoleList(List roleList) {
this.roleList = roleList;
}
public List getOtherContacts() {
return otherContacts;
}
public void setOtherContacts(List otherContacts) {
this.otherContacts = otherContacts;
}
}
同时在数据库中中添加相关的user数据
我的mongodb数据添加两个用户如下:
{
"_id" : ObjectId("558915caa668aa7b08eb1197"),
"_class" : "com.test.domain.entity.User",
"username" : "admin",
"password" : "202cb962ac59075b964b07152d234b70",
"permissionList" : ["parseResultAdd", "parseResultAddMulti", "usermanage", "loglist", "resultlist"],
"roleList" : ["admin"]
}
{
"_id" : ObjectId("55891777a668e496191c6eb1"),
"_class" : "com.test.domain.entity.User",
"username" : "test",
"password" : "202cb962ac59075b964b07152d234b70",
"permissionList" : ["parseResultAdd", "parseResultAddMulti", "resultlist"],
"roleList" : ["normal"]
}
"password" : "202cb962ac59075b964b07152d234b70"对应密码为123。
这里采用了shiro自带的加密方式。详情看下面的代码。
添加用户代码为:
package com.test.web.support.shiro;
import java.util.ArrayList;
import java.util.List;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import com.test.domain.entity.User;
import com.test.domain.repository.UserReposity;
public class UserAdd {
public static void main(String[] args) {
final String[] paths = new String[] {
"src/main/resource/com/test/web/conf/mongodb/spring-mongodb.xml"};
final ApplicationContext context = new FileSystemXmlApplicationContext(
paths); // ClassPathXmlApplicationContext
final UserReposity processor = (UserReposity) context
.getBean("userReposity");
User user=new User();
String username="admin";
String password="123";
user.setUsername(username);
String encrypted = new SimpleHash("MD5",password,null,1).toHex();
//这里的加密方式要与配置对应
// 指定hash算法为MD5; 无默认值,必须指定为MD5或者SHA-1等
// 指定散列次数为1次;默认为1
// 指定Hash散列值使用Hex加密存储。value="false"表明hash散列值用用Base64-encoded存储。默认为true
user.setPassword(encrypted);
List permissionList=new ArrayList();
List roleList=new ArrayList();
permissionList.add("parseResultAdd");
permissionList.add("parseResultAddMulti");
permissionList.add("usermanage");
permissionList.add("loglist");
permissionList.add("resultlist");
roleList.add("admin");
user.setPermissionList(permissionList);
user.setRoleList(roleList);
processor.saveObject(user);
}
}
String encrypted = new SimpleHash("MD5",password,null,1).toHex();
使用shiro注册增加用户时的加密方式要与自己的设置想匹配。
spring-shiro.xml中配置为:
验证时为:
添加后如图所示:
因为我们的是maven工程,所以把shiro相关的包写入pom.xml文件。
在pom.xml中添加
org.apache.shiro
shiro-core
1.2.2
org.apache.shiro
shiro-web
1.2.2
org.apache.shiro
shiro-spring
1.2.2
完整版的pom.xml太长,这里就不给出了,可下载源码查看
在web.xml里添加shiro 的配置
shiro的filter应该放在struts2的 filter的上面
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
shiroFilter
/*
完整版web.xml
encodingFilter
com.test.web.servlet.filter.EncodingFilter
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
encodingFilter
/*
shiroFilter
/*
springMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-web.xml
1
springMVC
/
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:spring-web.xml
_sid
COOKIE
404
/404
javax.servlet.ServletException
/error
*.jsp
UTF-8
false
主要是扩展AuthorizingRealm, 实现在数据库中查询是否有该帐号密码,实现验证。
我新建一个MyShiro的class
MyShiro.java
package com.test.web.support.shiro;
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.authc.UsernamePasswordToken;
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 org.springframework.beans.factory.annotation.Autowired;
import com.test.domain.entity.User;
import com.test.domain.repository.UserReposity;
public class MyShiro extends AuthorizingRealm{
@Autowired
UserReposity userReposity;
/**
* 权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录时输入的用户名
String loginName=(String) principalCollection.fromRealm(getName()).iterator().next();
//到数据库查是否有此对象
User user=userReposity.findByName(loginName);
if(user!=null){
//权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//用户的角色集合
info.addRoles(user.getRoleList());
//用户的角色对应的所有权限,如果只使用角色定义访问权限,下面的一行可以不要
info.addStringPermissions(user.getPermissionList());
return info;
}
return null;
}
/**
* 登录认证;
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authenticationToken) throws AuthenticationException {
//UsernamePasswordToken对象用来存放提交的登录信息
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
//查出是否有此用户
User user=userReposity.findByName(token.getUsername());
if(user!=null){
//若存在,将此用户存放到登录认证info中
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
}
return null;
}
}
同时还应配置mongodb的访问xml和userReposity的bean定义,这里不给出了,详情可下载源码
主要有两部分
一是对数据库具体访问的接口实现
二是 spring-mongodb.xml
HomeController.java
package com.test.web.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.test.domain.entity.User;
public class HomeController {
@RequestMapping(value="/login",method=RequestMethod.GET)
public String loginForm(Model model){
model.addAttribute("user", new User());
return "/login";
}
@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(User user,BindingResult bindingResult,RedirectAttributes redirectAttributes){
try {
if(bindingResult.hasErrors()){
return "/login";
}
//使用权限工具进行用户登录,登录成功后跳到shiro配置的successUrl中,与下面的return没什么关系!
SecurityUtils.getSubject().login(new UsernamePasswordToken(user.getUsername(), user.getPassword()));
return "/home";
} catch (AuthenticationException e) {
redirectAttributes.addFlashAttribute("message","用户名或密码错误");
return "redirect:/login";
}
}
@RequestMapping(value="/logout",method=RequestMethod.GET)
public String logout(RedirectAttributes redirectAttributes ){
//使用权限管理工具进行用户的退出,跳出登录,给出提示信息
SecurityUtils.getSubject().logout();
redirectAttributes.addFlashAttribute("message", "您已安全退出");
return "redirect:/login";
}
@RequestMapping("/403")
public String unauthorizedRole(){
return "/403";
}
}
三个页面放在views文件夹中 login.jsp,home.jsp,403.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
My JSP 'MyJsp.jsp' starting page
登录页面----${message }
用户名:
密 码:
submit
页面上的commandName的user需要与HomeController中
@RequestMapping(value="/login",method=RequestMethod.GET)
public String loginForm(Model model){
model.addAttribute("user", new User());
return "/login";
}
里的user对应。属性名对应。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
用户列表
${message }
用户列表--添加用户---退出登录
权限列表---- -当前登录用户名
用户已经登录显示此内容
admin角色登录显示此内容
normal角色登录显示此内容
**normal or admin 角色用户登录显示此内容**
loglist权限用户显示此内容
不具有loglist权限的用户显示此内容
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
权限错误
对不起,您没有权限请求此连接!
spring-shiro.xml
/login = anon
这里对页面的访问权限可以相应调节。
启动后分别用admin和test账户登录可以看到根据角色和权限已经能显示不同的内容
Controller中获取用户信息
shiro 管理登录,获取登录信息的方式常用的是:
Subject sub = SecurityUtils.getSubject();
Object obj = sub.getPrincipal();
这里的 obj 是字符串,还是某个实体,取决于 ShiroRealm 类的设置,代码如下:
也就是看doGetAuthenticationInfo方法中的存放的是实体还是具体某个字段。
/**
* 登录认证;
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authenticationToken) throws AuthenticationException {
//UsernamePasswordToken对象用来存放提交的登录信息
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
//查出是否有此用户
User user=userReposity.findByName(token.getUsername());
if(user!=null){
//若存在,将此用户存放到登录认证info中
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
return null;
}
如果像上面这样设置,SimpleAuthenticationInfo中存放的是user实体,读取登录信息就是
如果设置登录信息的地方如下:
/**
* 登录认证;
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authenticationToken) throws AuthenticationException {
//UsernamePasswordToken对象用来存放提交的登录信息
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
//查出是否有此用户
User user=userReposity.findByName(token.getUsername());
if(user!=null){
//若存在,将此用户存放到登录认证info中
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
}
return null;
}
SimpleAuthenticationInfo中存放的是user实体中username的字段,读取登录信息就是
String userName = (String) SecurityUtils.getSubject().getPrincipal();
realm如果不想用数据库,也可以用文本形式配置,如下
spring-shiro.xml中注释mongoRealm,启用iniRealm
新建shiro.ini
shiro.ini 里是帐号密码和角色
[users]
admin = 123, admin
test = 123, normal
[roles]
normal= *
admin = *
当然还可以有其它配置
源码下载:
springshiro