ssm整合shiro通過自定義Realm實現認證登入、許可權處理、自定義role攔截、MD5加密
阿新 • • 發佈:2018-12-14
整合後實現功能
1.登入認證 2.許可權處理 3.自定義role攔截 4.md5加密
ssm整合shiro步驟
先看看整合完成後的專案結構
新建一個maven專案
配置pom.xml檔案
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>top.maniy</groupId> <artifactId>shiro-ssm</artifactId> <version>1.0-SNAPSHOT</version> <properties> <junit.version>4.12</junit.version> <spring.version>4.1.3.RELEASE</spring.version> <mybatis.version>3.2.8</mybatis.version> <mybatis.spring.version>1.2.2</mybatis.spring.version> <mybatis.paginator.version>1.2.15</mybatis.paginator.version> <mysql.version>5.1.32</mysql.version> <slf4j.version>1.6.4</slf4j.version> <jackson.version>2.4.2</jackson.version> <druid.version>1.0.9</druid.version> <jstl.version>1.2</jstl.version> <servlet-api.version>2.5</servlet-api.version> <jsp-api.version>2.0</jsp-api.version> <commons-lang3.version>3.3.2</commons-lang3.version> <commons-io.version>1.3.2</commons-io.version> <commons-net.version>3.3</commons-net.version> <pagehelper.version>3.4.1</pagehelper.version> <shiro-spring>1.2.3</shiro-spring> <shiro-core>1.2.3</shiro-core> </properties> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- Mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis.spring.version}</version> </dependency> <dependency> <groupId>com.github.miemiedev</groupId> <artifactId>mybatis-paginator</artifactId> <version>${mybatis.paginator.version}</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>${pagehelper.version}</version> </dependency> <!-- Apache工具元件 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>${commons-io.version}</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>${commons-net.version}</version> </dependency> <!-- Jackson Json處理工具包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <!-- 單元測試 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- 日誌處理 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <!-- JSP相關 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro-core}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro-spring}</version> </dependency> </dependencies> </project>
進行SSM框架整合
通過project Structure新建webpp及其下面目錄
新建專案結構資料夾及檔案
sqlMapConfig.xml、spring-service、spring-dao、jdbc.properites與下面連結相同
spring-shiro.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="login.html"/> <property name="unauthorizedUrl" value="403.html" /> <property name="filterChainDefinitions"> <value> <!-- 這裡順序執行 anon不要認證 authc需要認證,一般情況下 /*放在最下面--> <!--載入靜態資源 /js/** = anon--> /login.html = anon /subLogin = anon /testRole2=roles["admin"] /testRole3=rolesOr["admin","admin1"] /testPerms =perms[user:select] /testPerms1 =perms["user:select","user:update"] /* = authc </value> </property> <property name="filters"> <util:map> <entry key="rolesOr" value-ref="rolesOrFilter"/> </util:map> </property> </bean> <bean class="top.maniy.demo.filter.RolesOrFilter" id="rolesOrFilter"/> <!--建立SecurityManager物件 --> <bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager"> <property name="realm" ref="realm"/> </bean> <!--自定義realm --> <bean class="top.maniy.demo.shiro.realm.CustomRealm" id="realm"> <property name="credentialsMatcher" ref="credentialsMatcher" /> </bean> <!--md5 加密--> <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher" id="credentialsMatcher"> <property name="hashAlgorithmName" value="md5" /> <property name="hashIterations" value="1"/> </bean> </beans>
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!-- 配置Controller掃描 --> <context:component-scan base-package="top.maniy.demo.controller" /> <!-- 配置註解驅動 --> <mvc:annotation-driven /> <!-- 對靜態資源放行 --> <!--<mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/js/" mapping="/js/**"/> <mvc:resources location="/fonts/" mapping="/fonts/**"/>--> <!-- 2.靜態資源預設servlet配置 (1)加入對靜態資源的處理:js,gif,png (2)允許使用"/"做整體對映 --> <mvc:resources mapping="/*" location="WEB-INF/" /> <!-- 配置檢視解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <!-- 字首 --> <property name="prefix" value="/WEB-INF/page/" /> <!-- 字尾 --> <property name="suffix" value=".jsp" /> </bean> <aop:config proxy-target-class="true"/> <!--Shiro配置--> <!-- 1.配置lifecycleBeanPostProcessor,可以在Spring IOC容器中呼叫shiro的生命週期方法. --> <bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- 2.開啟Spring AOC Shiro註解支援 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
<!--配置shiro-->
<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>
<!-- 配置spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-*.xml</param-value>
</context-param>
<!-- 配置監聽器載入spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置過濾器,解決post的亂碼問題 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置SpringMVC -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<!-- 配置springmvc什麼時候啟動,引數必須為整數 -->
<!-- 如果為0或者大於0,則springMVC隨著容器啟動而啟動 -->
<!-- 如果小於0,則在第一次請求進來的時候啟動 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 所有的請求都進入springMVC -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
自定義role攔截RolesOrFilter
/**
* @author liuzonghua
* @Package top.maniy.filter
* @Description:自定義role攔截,定義:如果有一個許可權存在就可以跳轉
* @date 2018/10/9 12:57
*/
public class RolesOrFilter extends AuthorizationFilter{
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
Subject subject =getSubject(servletRequest,servletResponse);
String[] roles =(String[]) o;
if(roles ==null || roles.length == 0){
return true;
}
for (String role:roles){
if(subject.hasRole(role)){
return true;
}
}
return false;
}
}
UserMapper.java
public interface UserMapper {
//查詢根據username使用者資訊
User getUserByUserName(String userName);
//根據username查詢角色
List<String> queryRolesByUserName(String userName);
//根據username查詢許可權
List<String> queryPermissionByUserName(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 ="top.maniy.demo.mapper.UserMapper">
<select id="getUserByUserName" resultType="User">
SELECT * FROM users WHERE username=#{username}
</select>
<select id="queryRolesByUserName" resultType="String">
SELECT role_name FROM user_roles WHERE username=#{username}
</select>
<select id="queryPermissionByUserName" resultType="String">
SELECT permission FROM roles_permissions WHERE role_name=#{role_name}
</select>
</mapper>
自定義CustomRealm
public class CustomRealm extends AuthorizingRealm{
@Autowired
private UserMapper userMapper;
// Map<String,String> userMap =new HashMap<String, String>(16);
// {
// userMap.put("maniy","993121f227e2cef658c392549708d60c");
// super.setName("customRealm");
// }
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String userName = (String) principalCollection.getPrimaryPrincipal();
Set<String> roles =getRolesByUserName(userName);
Set<String> permissions = getPermissionByUserName(userName);
SimpleAuthorizationInfo simpleAuthorizationInfo =new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setStringPermissions(permissions);
simpleAuthorizationInfo.setRoles(roles);
return simpleAuthorizationInfo;
}
private Set<String> getPermissionByUserName(String userName) {
List<String> listR =userMapper.queryRolesByUserName(userName);
List<String>listP=new ArrayList<String>();
for(String str:listR){
listP.addAll(userMapper.queryPermissionByUserName(str));
}
Set<String> sets =new HashSet<String>(listP);
// Set<String> sets =new HashSet<String>();
// sets.add("user:delete");
// sets.add("user:add");
return sets;
}
private Set<String> getRolesByUserName(String userName) {
System.out.println("從資料庫中獲取授權資料");
List<String> list =userMapper.queryRolesByUserName(userName);
Set<String> sets=new HashSet<String>(list);
// Set<String> sets =new HashSet<String>();
// sets.add("admin");
// sets.add("user");
return sets;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
//1.從主體傳過來額認證資訊中,獲得使用者名稱
String userName = (String) authenticationToken.getPrincipal();
//2.通過使用者名稱到資料庫中獲取憑證
String password = getPasswordByUserName(userName);
if(password == null){
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo =new SimpleAuthenticationInfo
(userName,password,"customRealm");
//shiro需要知道用了什麼鹽,在去解析密碼
simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userName));
return simpleAuthenticationInfo;
}
/**
* 模擬資料庫查詢認證
* @param username
* @return
*/
private String getPasswordByUserName(String username){
//
User user =userMapper.getUserByUserName(username);
if(user!=null){
System.out.println(user.getPassword());
return user.getPassword();
}else {
return null;
}
//return userMap.get(username);
}
public static void main(String[] args) {
//單一的是密碼加密容易破解,這時候就需要 加鹽
Md5Hash md5Hash= new Md5Hash("1234567","Mark");
System.out.println(md5Hash.toString());
}
}
UserController
@Controller
public class UserController {
@RequestMapping(value = "/subLogin" ,method = RequestMethod.POST,
produces = "application/json;charset=utf-8")
@ResponseBody
public String subLogin(User user){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token =new UsernamePasswordToken(user.getUsername(),
user.getPassword());
try {
token.setRememberMe(user.isRememberMe());
subject.login(token);
} catch (AuthenticationException e) {
return e.getMessage();
}
if(subject.hasRole("admin")){
if (subject.isPermitted("user:select")){
return "許可權為user:select";
}
return "有admin許可權";
}
return "無admin許可權";
}
/**
* 通過註解配置授權
* 使用者角色必須具備admin許可權才能訪問
* @return
*/
@RequiresRoles("admin")
//@RequiresPermissions("xxxx")
@RequestMapping(value = "/testRole",method = RequestMethod.GET)
@ResponseBody
public String TestRole(){
return "testRole success";
}
/**
* 通過註解配置授權
* 使用者角色必須具備admin許可權才能訪問
* @return
*/
@RequiresRoles("admin1")
@RequestMapping(value = "/testRole1",method = RequestMethod.GET)
@ResponseBody
public String TestRole1(){
return "testRole1 success";
}
@RequestMapping(value = "/testRole2",method = RequestMethod.GET)
@ResponseBody
public String TestRole2(){
return "testRole2 success";
}
@RequestMapping(value = "/testRole3",method = RequestMethod.GET)
@ResponseBody
public String TestRole3(){
return "testRole3 success";
}
@RequestMapping(value = "/testPerms",method = RequestMethod.GET)
@ResponseBody
public String TestPerms(){
return "testPerms success";
}
@RequestMapping(value = "/testPerms1",method = RequestMethod.GET)
@ResponseBody
public String TestPerms1(){
return "testPerms1 success";
}
}
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登入</title>
</head>
<body>
<form action="subLogin" method="post">
<input type="text" name="username" /><br>
<input type="password" name="password"/><br>
<input type="checkbox" name="rememberMe" />記住我
<input type="submit" value="登入">
</form>
</body>
</html>