欢迎访问优讯网!
您当前的位置:首页 > 爱编程

spring boot+mybatis+shiro对url动态授权,同一账号登录,踢出最早登录

时间:2020-01-13 08:14:18  来源:优讯网  作者:小卡司  浏览次数:

老规矩开始之前的两问:干什么,为什么这么干

场景:

根本问题:任何多用户的系统都存在身份鉴权。简单来说,不同用户在同一个系统有不同的操作,那么系统必然要识别用户。

产生问题:身份识别之后,对于一个系统来说,就可以进行正常使用,但是这个时候任何人都可以获得系统的信息,这就产生了授权。

为什么使用shiro?

shiro是一款专门用来身份识别与授权的框架

shiro能干什么?

进行身份识别和授权

开始:

1:pom.xml 引入相关包

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.2.2</version>
</dependency>

2:首先是身份识别的问题,一般的我们都是通过输入的用户名和密码去数据库进行比对

那么对于shiro来说,我们只需要准备前端传的参数和数据库的参数,shiro就会为我们自动比对

(1)前端数据:

<from>
   <input name="username"/>
   <input name="password">
   <input type="submit">
</from>

  (2) 数据库

CREATE TABLE `fsp_user` (
  `UUID` varchar(50) NOT NULL,
  `F_NICKNAME` varchar(100) DEFAULT NULL,
  `F_PASSWORD` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`UUID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO 
`fsp_user` 
VALUES 
('90feec5c-67bd-4fb2-b360-8b0387c4c009', 
'admin', 
'87632a5ef1d47286da9c1361717a1312');

  (3)登录比对 

  这一步是由shiro来完成,shiro需要知道我们的 输入参数和数据库的数据

  在此之前shiro需要初始化

 shiro的中心管理器是SecurityManager,那么第一步就是要配置SecurityManager

@Bean
public SecurityManager securityManager() {
    //new 一个DefaultWebSecurityManager
    DefaultSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
    //realm 就是从数据库取出数据比对登录
    defaultSecurityManager.setRealm(myShiroRealm());
    //session管理器
    defaultSecurityManager.setSessionManager(sessionManager());
    //cache管理器
    defaultSecurityManager.setCacheManager(cacheManager());

    //我们需要对密码进行加密 使用md5,加密10次
    HashedCredentialsMatcher hashedCredentialsMatcher  = new HashedCredentialsMatcher("md5");
    hashedCredentialsMatcher.setHashIterations(10);
    myShiroRealm().setCredentialsMatcher(hashedCredentialsMatcher);

    SecurityUtils.setSecurityManager(defaultSecurityManager);
    return defaultSecurityManager;

}
@Bean
//session 管理器
public DefaultWebSessionManager sessionManager(){
    DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
    SimpleCookie simpleCookie= new SimpleCookie();
    simpleCookie.setName("jeesite.session.id");
    defaultWebSessionManager.setSessionIdCookie(simpleCookie);
    defaultWebSessionManager.setSessionDAO(sessionDAO());
    return defaultWebSessionManager;
}
//session的增删改查操作
@Bean
public MemorySessionDAO sessionDAO(){
    return new MemorySessionDAO();
}
//cache管理器
@Bean
public CacheManager cacheManager(){
    return new EhCacheManager();
}
@Bean
//取出数据库的数据  这个是我们自定义的
public UserRealm myShiroRealm(){
    return new UserRealm();
}
//我们定义的数据源集成自AuthorizingRealm 
public class UserRealm extends AuthorizingRealm {
    private Logger logger = LoggerFactory.getLogger(AuthorizingRealm.class);
    //数据库fsp_user 表对应的mybatis mapper接口
    @Autowired
    private FspUserDao fspUserDao;
    
 

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
 principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        return authorizationInfo;
    }

    //登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken 
authenticationToken) throws AuthenticationException {
        //1,获得前端传值
        String username = (String) authenticationToken.getPrincipal();
        //去数据库查询
        FspUser user = fspUserDao.isSelect("F_IPONE",username);
        if (user == null) {
            //没找到帐号
            throw new UnknownAccountException();
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user, user.getF_PASSWORD(), "");
        //盐
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("GGZEServer"));
        user.setF_PASSWORD("");
        //将用户信息放入session中
        SecurityUtils.getSubject().getSession().setTimeout(-5000);
        SecurityUtils.getSubject().getSession().setAttribute("FSPUSER", user);
        return authenticationInfo;
    }

    /*//加密
    public static void main(String[] args){
        Md5Hash md5Hash = new Md5Hash("123456","GGZEServer",10);
        System.out.println(md5Hash.toString());
    }*/

}

(4)配置完成后,我们需要让所有的请求都是合法的,就必须进行登录,记住登录信息,每次的请求验证其合法性

我们使用过滤器来过滤所有请求,

首先要使shiro认识我们自定义的过滤器

@Bean
public AutoShiro shirFilter(SecurityManager securityManager, FspDataRecordDao
 fspDataRecordDao) {
    System.out.println("ShiroConfiguration.shirFilter()");

    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
   // 过滤器链11 
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
     
    //key 为访问地址,value为权限。anao全部不过滤 authc为需要登录 loingout为登出
    filterChainDefinitionMap.put("/css/**", "anon");
    filterChainDefinitionMap.put("/login", "authc");
    filterChainDefinitionMap.put("/img/**", "anon"); 
    filterChainDefinitionMap.put("/js/**", "anon"); 
    filterChainDefinitionMap.put("/loginout", "loginout");


    shiroFilterFactoryBean.setSecurityManager(securityManager);
    //登录地址设置
    shiroFilterFactoryBean.setLoginUrl("/vsp_8201574998956");
    //成功地址设置
    shiroFilterFactoryBean.setSuccessUrl("/vsp_8201574998957");

    Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
    AuthFilter authFilter=new AuthFilter();
    authFilter.setLoginUrl("/login");
    authFilter.setUsernameParam("F_IPONE");
    authFilter.setPasswordParam("F_PASSWORD");
    authFilter.setUserClass(FspUser.class);
    //设置过滤器名
    filters.put("authc", authFilter);
    //这里可以设置自定义的过滤器
    //设置登出
    LogoutFilter logoutFilter=new LogoutFilter();
    filters.put("loginout",logoutFilter);
    shiroFilterFactoryBean.setFilters(filters);

    return shiroFilterFactoryBean;

}

按以上配置,shiro会认知shiro的过滤器,我们来实现它的过滤器

public class AuthFilter extends FormAuthenticationFilter {
  
    private Class<? extends FspUser> userClass;
  
    private static final String REDIRECT_URL_PARAMETER_NAME = "redirectUrl";


    //创建身份认证
    @Override
    protected org.apache.shiro.authc.AuthenticationToken createToken(ServletRequest 
servletRequest, ServletResponse servletResponse) {
        String username = getUsername(servletRequest);
        String password = getPassword(servletRequest);
        boolean rememberMe = isRememberMe(servletRequest);
        String host = getHost(servletRequest);
        return new UsernamePasswordToken(username, password, rememberMe, host);
    }

    /**
     * 是否允许访问
     *
     * @param servletRequest  ServletRequest
     * @param servletResponse ServletResponse
     * @param mappedValue     映射值
     * @return 是否允许访问
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest,
 ServletResponse servletResponse, Object mappedValue) {
        Subject subject = getSubject(servletRequest, servletResponse);
        Object principal = subject != null ? subject.getPrincipal() : null;
        if (principal == null || !FspUser.class.isAssignableFrom(principal.getClass())) {
            return false;
        }
        HttpServletRequest request=(HttpServletRequest) servletRequest;
        if(request.getServletPath().indexOf("login")>=0&&request.getSession().
getAttribute("FSPUSER")!=null){
            HttpServletResponse response = (HttpServletResponse)servletResponse;
            try {
                response.sendRedirect("/shopc/vsp_8201574998957");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return super.isAccessAllowed(servletRequest, servletResponse, mappedValue);
    }

    /**
     * 拒绝访问处理
     *
     * @param servletRequest  ServletRequest
     * @param servletResponse ServletResponse
     * @return 是否继续处理
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest,
 ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                return executeLogin(request, response);
            } else {
                return true;
            }
        }
        response.sendRedirect("/shopc/vsp_8201574998956");
        return false;
    }

    /**
     * 登录成功处理
     *
     * @param authenticationToken 令牌
     * @param subject             Subject
     * @param servletRequest      ServletRequest
     * @param servletResponse     ServletResponse
     * @return 是否继续处理
     */
    @Override
    protected boolean onLoginSuccess(org.apache.shiro.authc.AuthenticationToken 
authenticationToken, Subject subject, ServletRequest servletRequest,
 ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        return super.onLoginSuccess(authenticationToken, subject, servletRequest, 
servletResponse);
    }

    /**
     * 登录失败处理
     *
     * @param authenticationToken     令牌
     * @param authenticationException 认证异常
     * @param servletRequest          ServletRequest
     * @param servletResponse         ServletResponse
     * @return 是否继续处理
     */
    @Override
    protected boolean onLoginFailure(org.apache.shiro.authc.AuthenticationToken 
authenticationToken, AuthenticationException authenticationException, 
ServletRequest servletRequest, ServletResponse servletResponse) {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        return super.onLoginFailure(authenticationToken, authenticationException,
 servletRequest, servletResponse);
    }

    public Class<? extends FspUser> getUserClass() {
        return userClass;
    }

    public void setUserClass(Class<? extends FspUser> userClass) {
        this.userClass = userClass;
    }

    public static String getRedirectUrlParameterName() {
        return REDIRECT_URL_PARAMETER_NAME;
    }

当执行创建身份认证的时候return new UsernamePasswordToken(username, password, rememberMe, host);

会进去我们自定义的Realm 登录成功。

已上传码云:https://gitee.com/wervernice/shirotest

未完待续

来顶一下
返回首页
返回首页

原文链接:https://my.oschina.net/u/3188070/blog/3156291


推荐资讯
如何下载旧版centos iso镜像 如何下载迷你mini版的centos镜像
如何下载旧版centos i
计算机的正确使用姿势 电脑痴如何正确的使用电脑
计算机的正确使用姿势
好用的后台管理的前端框架模版H-ui H-ui框架模版分享
好用的后台管理的前端
微信电脑多开方法 无需辅助电脑版微信双开方法分享
微信电脑多开方法 无
相关文章
栏目更新
栏目热门