zoukankan      html  css  js  c++  java
  • springboot集成shiro实现身份认证

     github地址:https://github.com/peterowang/shiro

    pom文件

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <!-- mysql驱动; -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
    <groupId>net.sourceforge.nekohtml</groupId>
    <artifactId>nekohtml</artifactId>
    <version>1.9.22</version>
    </dependency>

    <!--shiro-->
    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.2.2</version>
    </dependency>

    <!-- Spirng data JPA依赖; -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    </dependency>
    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    </dependency>
    <dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
    <exclusions>
    <exclusion>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    </dependencies>

    1.集成spring data jpa 

    2.使用thymeleaf   见application.properties

    spring.application.name=spring-boot-shiro
    server.port=8080

    spring.thymeleaf.mode=LEGACYHTML5 这里的设置主要是因为thymeleaf校验html文件的时候会特别严格,比如<input> 必须加上/结尾,这里需要依赖nekohtml.
    spring.thymeleaf.cache=false
    spring.thymeleaf.prefix=classpath:/templates/ 这里相当于springmvc里的视图解析器
    spring.thymeleaf.suffix=.html


    ########################################################
    ###datasource
    ########################################################
    spring.datasource.url = jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8
    spring.datasource.username = root
    spring.datasource.password = root
    spring.datasource.driverClassName = com.mysql.jdbc.Driver
    spring.datasource.max-active=20
    spring.datasource.min-active=10
    spring.datasource.max-idle=8
    spring.datasource.initial-size=10



    ########################################################
    ### Java Persistence Api
    ########################################################
    # Specify the DBMS
    spring.jpa.database = MYSQL
    # Show or not log for each sql query
    spring.jpa.show-sql = true
    # Hibernate ddl auto (create, create-drop, update)
    spring.jpa.hibernate.ddl-auto = update
    # Naming strategy
    #[org.hibernate.cfg.ImprovedNamingStrategy | org.hibernate.cfg.DefaultNamingStrategy]
    spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.DefaultNamingStrategy
    # stripped before adding them to the entity manager)
    spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
    目录结构 :

    3.配置realm

    Realm是一个Dao,通过它来验证用户身份和权限。这里Shiro不做权限的管理工作,需要我们自己管理用户权限,只需要从我们的数据源中把用户和用户的角色权限信息取出来交给Shiro即可。
    config包下再建一个包Shiro,然后在Shiro包下建一个MyShiroRealm类,继承AuthorizingRealm抽象类。
    package com.example.demo.config.shiro;

    import com.example.demo.model.UserInfo;
    import com.example.demo.service.UserInfoService;
    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 org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;

    /**
    * Created by BFD-593 on 2017/8/8.
    */
    public class MyShiroRealm extends AuthorizingRealm{
    private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
    @Autowired
    private UserInfoService userInfoService;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    logger.info("开始身份验证");
    String username = (String) token.getPrincipal();
    UserInfo userInfo = userInfoService.findByUsername(username);
    if(userInfo==null) {
    return null;
    }
    SimpleAuthenticationInfo auth = new SimpleAuthenticationInfo(
    userInfo,
    userInfo.getPassword(), //密码
    getName() //realm name
    );
    return auth;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    return null;
    }
    }

    4.配置自定义密码比较器(shiro会根据这个来将用户输入的密码加密成注册时的密码,与db里的密码比较)
    package com.example.demo.config.shiro;

    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
    import org.apache.shiro.crypto.hash.Md5Hash;

    /**
    * Created by BFD-593 on 2017/8/8.
    */
    public class CredentialsMatcher extends SimpleCredentialsMatcher {

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    UsernamePasswordToken utoken=(UsernamePasswordToken) token;
    //获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
    String password = String.valueOf(utoken.getPassword());
    String username = String.valueOf(utoken.getUsername());
    Md5Hash md5 = new Md5Hash(password,username, 2);
    String inPassword = md5.toString();
    //获得数据库中的密码
    String dbPassword=(String) info.getCredentials();
    //进行密码的比对
    return this.equals(inPassword, dbPassword);
    }

    }
    5.shiroConfig配置类
    这里要配置的是ShiroConfig类,Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。 既然是使用 Filter 一般也就能猜到,是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。
    package com.example.demo.config.shiro;

    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    import java.util.LinkedHashMap;
    import java.util.Map;

    /**
    * Created by BFD-593 on 2017/8/8.
    */
    @Configuration
    public class ShiroConfiguration {
    @Bean(name="shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager manager) {

    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    shiroFilterFactoryBean.setSecurityManager(manager);

    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    filterChainDefinitionMap.put("/logout", "logout");
    filterChainDefinitionMap.put("/favicon.ico", "anon");
    filterChainDefinitionMap.put("/**", "authc");
    //authc表示需要验证身份才能访问,还有一些比如anon表示不需要验证身份就能访问等。
    //关于为什么设置filterChainDefinitionMap.put("/favicon.ico", "anon");,请参考Shiro登录后下载favicon.ico问题

    shiroFilterFactoryBean.setLoginUrl("/login");
    shiroFilterFactoryBean.setSuccessUrl("/index");
    // shiroFilterFactoryBean.setUnauthorizedUrl("/403"); //这里设置403并不会起作用,参考http://www.jianshu.com/p/e03f5b54838c

    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactoryBean;
    }


    /**
    * 不指定名字的话,自动创建一个方法名第一个字母小写的bean
    * @Bean(name = "securityManager")
    * @return
    */
    @Bean(name="securityManager")
    public SecurityManager securityManager(@Qualifier("authRealm") MyShiroRealm authRealm) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(authRealm);
    return securityManager;
    }

    /**
    * Shiro Realm 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的
    *
    * @param
    * @return
    */
    @Bean(name="authRealm")
    public MyShiroRealm userRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
    MyShiroRealm userRealm = new MyShiroRealm();
    //告诉realm,使用credentialsMatcher加密算法类来验证密文
    userRealm.setCredentialsMatcher(matcher);
    return userRealm;
    }

    /**
    * 密码比较器
    * @return
    */
    @Bean(name="credentialsMatcher")
    public CredentialsMatcher credentialsMatcher() {
    return new CredentialsMatcher();
    }
    }

    6.web层
    package com.example.demo.web;

    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;

    import javax.servlet.http.HttpServletRequest;
    import java.util.Map;

    /**
    * Created by BFD-593 on 2017/8/8.
    */
    @Controller
    public class HomeController {
    @RequestMapping({"/","/index"})
    public String index() {
    return "index";
    }

    /**
    * logout由shiro实现,我们只需提供入口即可
    * filterChainDefinitionMap.put("/logout", "logout");
    * @return
    */
    @RequestMapping({"/logout"})
    public String logout(){
    return "login";
    }

    /**
    * 因为设置了setLoginUrl("/login");登录url如果没有登录,
    * 所有的请求都发送到这里。shiro会自动调用securityManager
    * 此方法不处理登录成功,由shiro进行处理。
    * @param request
    * @param map
    * @return
    * @throws Exception
    */
    @RequestMapping("/login")
    public String login(HttpServletRequest request, Map<String, Object> map) throws Exception {
    // 登录失败从request中获取shiro处理的异常信息。
    // shiroLoginFailure:就是shiro异常类的全类名.
    String exceptionClassName = (String)request.getAttribute("shiroLoginFailure");
    String error = null;
    if(UnknownAccountException.class.getName().equals(exceptionClassName)) {
    error = "用户名/密码错误";
    } else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {
    error = "用户名/密码错误";
    } else if(exceptionClassName != null) {
    error = "其他错误:" + exceptionClassName;
    }
    map.put("msg", error);
    return "login";
    }
    }
    7.UserInfo:
    package com.example.demo.model;

    import javax.persistence.*;
    import java.io.Serializable;

    /**
    * Created by archerlj on 2017/6/30.
    */

    @Entity
    @Table(name="user_info")
    public class UserInfo implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;//用户id;

    @Column(unique = true, name = "username")
    private String username;//账号.
    @Column(name = "password")
    private String password; //密码;
    @Column(name = "salt")
    private String salt;//加密密码的盐
    @Column(name = "state")
    private byte state;//用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.


    public long getId() {
    return id;
    }

    public void setId(long id) {
    this.id = id;
    }

    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 getSalt() {
    return salt;
    }

    public void setSalt(String salt) {
    this.salt = salt;
    }

    public byte getState() {
    return state;
    }

    public void setState(byte state) {
    this.state = state;
    }


    }
    8.UserInfoRespository
    package com.example.demo.dao;

    import com.example.demo.model.UserInfo;
    import org.springframework.data.jpa.repository.JpaRepository;

    /**
    * Created by BFD-593 on 2017/8/8.
    */
    public interface UserInfoRepository extends JpaRepository<UserInfo,Long> {
    public UserInfo findByUsername(String username);

    public UserInfo save(UserInfo userInfo);
    }
    9.UserInfoService:
    import com.example.demo.dao.UserInfoRepository;
    import com.example.demo.model.UserInfo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    /**
    * Created by BFD-593 on 2017/8/8.
    */
    @Service
    public class UserInfoService {
    @Autowired
    private UserInfoRepository userInfoRepository;

    public UserInfo findByUsername(String username){
    return userInfoRepository.findByUsername(username);
    }
    }
    10.配置jpa请看之前博客
  • 相关阅读:
    树形结构基础
    最长公共子序列
    四 过滤模式 map Only
    三 概要模式 2) MR倒排索引、性能分析、搜索干扰词。
    三 概要模式 1)数值概要 (单词计数记录计数最大值/最小值/计数平均值、中位数、标准差)
    一 梳理 从 HDFS 到 MR。
    个人学习源码的 HBase误区的总结 与 架构图
    15 hbase 学习(十五)缓存机制以及可以利用SSD作为存储的BucketCache
    13 hbase源码系列(十三)缓存机制MemStore与Block Cache
    HBase 系统架构
  • 原文地址:https://www.cnblogs.com/wangjing666/p/7323782.html
Copyright © 2011-2022 走看看