基于SpringBoot实现简易版登录功能

通常我们做一个后台系统,不可避免的需要做一些安全性的拦截,但是又不想做的太过麻烦,只要能够通过帐号密码登录基本上就差不多了,还可以拓展一些特定密钥免登录小功能。

今天给大家示范一个基于SpringBoot的实现的基本步骤:
大概流程图

功能:

  1. 登录
  2. 登出
  3. token免登录

构建基础配置项

1. 注册拦截器

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"扫描你的controller地址"})
public class MvcConfigBean extends WebMvcConfigurerAdapter {

    @Autowired
    private LoginHandler loginHandler;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        super.addResourceHandlers(registry);
        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
        registry.addResourceHandler("/lib/**").addResourceLocations("classpath:/static/lib/");
        registry.addResourceHandler("/fonts/**").addResourceLocations("classpath:/static/fonts/");
        registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
     registry.addInterceptor(loginHandler).addPathPatterns("/**")
     		// 排除登录的Service验证以及跳转登录页的信息
            .excludePathPatterns(ServerConstants.LOGIN_HTML_PATH, ServerConstants.LOGIN_PATH)
            // 过滤静态资源文件
            .excludePathPatterns("/js/**", "/css/**", "/lib/**", "/fonts/**", "/images/**");
    }
}

拦截器的实现

这里负责拦截所有的请求,统一要经过这边验证,如果没有携带token相关的,统一返回登录页。


@Component
public class LoginHandler implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(LoginHandler.class);

    @Autowired
    private JayServerProperties serverProperties;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        logger.info(request.getRequestURI().toString());
		// 特定的token
        String token = request.getParameter("token");

        String defaultToken = serverProperties.getToken();
        
		// 如果携带的是特定的token,那么直接放行
        if (defaultToken.equals(token)) {
            CookiesUtil.setCookie(response, ServerConstants.USER_SESSION_KEY, token, -1);
            return true;
        }
        
		// 从客户端的cookie中获取登录token
        Cookie cookieByName = CookiesUtil.getCookieByName(request, ServerConstants.USER_SESSION_KEY);

        if (cookieByName != null && defaultToken.equals(cookieByName.getValue())) {
            return true;
        }
		// 如果是session级别的token也直接放行
        String user = (String)request.getSession().getAttribute(ServerConstants.USER_SESSION_KEY);
		// 如果没有得到配置内的token,那么请登录
        if (StringUtils.isEmpty(user)) { response.sendRedirect(ServerConstants.LOGIN_HTML_PATH);
            logger.info("token 校验失败.");
            return false;
        }

        return true;
    }
}

配置文件

@ConfigurationProperties(prefix = "jay.server")
public class JayServerProperties {

    private String token;

    private String username;

    private String password;

    // 省略get set ...
}

可以在yml中配置帐号密码和特定的token信息

jay:
  server:
    token: xxxx
    username: admin
    password: xxxx

路由层

其中包含了登录验证、登录页、登出等请求处理。。

/**
 * @author : liukx
 * @describe :首页
 * @time : 2019/3/1 - 16:31
 */
@Controller
@RequestMapping(value = "/")
public class IndexController {
    final static private String page = "/";
    
    @Autowired
    private JayServerProperties serverProperties;

    @RequestMapping(value = "/index.html", method = RequestMethod.GET)
    public String index() throws Exception {
        return page + "index";
    }

    @RequestMapping(value = "/login.html", method = RequestMethod.GET)
    public String login() throws Exception {
        return page + "login";
    }

    @RequestMapping(value = "/loginOut.html", method = RequestMethod.GET)
    public String loginOut(HttpServletRequest request, HttpServletResponse response) throws Exception {
        CookiesUtil.deleteCookieByName(request, response, ServerConstants.USER_SESSION_KEY);
        return "redirect:/login.html";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public ResponseCommonModel loginService(HttpServletResponse response, @RequestBody LoginRequest loginRequest)
        throws Exception {
        String username = serverProperties.getUsername();
        String password = serverProperties.getPassword();
        String token = serverProperties.getToken();

        String un = loginRequest.getUsername();
        String pwd = loginRequest.getPassword();

        if (username.equals(un) && password.equals(pwd)) {
            CookiesUtil.setCookie(response, ServerConstants.USER_SESSION_KEY, token, -1);
            return ResponseUtils.trues();
        } else {
            return ResponseUtils.falses(CommonEnums.LOGIN_ERROR);
        }

    }

其他

这里包含一些工具类、或者常量类.

public class CookiesUtil {

    /**
     * 根据名字获取cookie
     *
     * @param request
     * @param name    cookie名字
     * @return Cookie
     */
    public static Cookie getCookieByName(HttpServletRequest request, String name) {
        Map<String, Cookie> cookieMap = readCookieMap(request);
        if (cookieMap.containsKey(name)) {
            Cookie cookie = (Cookie)cookieMap.get(name);
            return cookie;
        } else {
            return null;
        }
    }

    /**
     * 将cookie封装到Map里面
     *
     * @param request
     * @return Map<String, Cookie>
     */
    private static Map<String, Cookie> readCookieMap(HttpServletRequest request) {
        Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            for (Cookie cookie : cookies) {
                cookieMap.put(cookie.getName(), cookie);
            }
        }
        return cookieMap;
    }

    /**
     * 保存Cookies
     *
     * @param response response响应
     * @param name     cookie的名字
     * @param value    cookie的值
     * @param time     cookie的存在时间(秒)
     */
    public static HttpServletResponse setCookie(HttpServletResponse response, String name, String value, int time) {
        // new一个Cookie对象,键值对为参数
        Cookie cookie = new Cookie(name, value);
        // tomcat下多应用共享
        cookie.setPath("/");
        // 如果cookie的值中含有中文时,需要对cookie进行编码,不然会产生乱码
        try {
            URLEncoder.encode(value, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 单位:秒
        cookie.setMaxAge(time);
        // 将Cookie添加到Response中,使之生效
        response.addCookie(cookie); // addCookie后,如果已经存在相同名字的cookie,则最新的覆盖旧的cookie
        return response;
    }

    /**
     * <p>删除无效cookie</p>
     * <p>无效☞1.过时 2.未发布</p>
     *
     * @param request   请求
     * @param response  响应
     * @param deleteKey 需要删除cookie的名称
     */
    public static void deleteCookieByName(HttpServletRequest request, HttpServletResponse response, String deleteKey)
        throws NullPointerException {
        Map<String, Cookie> cookieMap = readCookieMap(request);
        for (String key : cookieMap.keySet()) {
            if (key.equals(deleteKey)) {
                Cookie cookie = cookieMap.get(key);
                // 默认值是-1,即:关闭浏览器时就清除cookie;
                // 当设置为0的时候:创建完cookie,使用后马上就删除;
                // 因为时间到了,又因为,cookie没有清除方法,所以设置为 0,就相当于清除方法;
                // 当设置时间大于0,当时间到达后就会自动删除
                cookie.setMaxAge(0);//设置cookie有效时间为0
                cookie.setPath("/");//不设置存储路径
                response.addCookie(cookie);
            }
        }
    }
}

常量类

public class ServerConstants {

    public static String INDEX_HOME = "/index.html";
    public static String USER_SESSION_KEY = "JAY_TOKEN";
    public static String LOGIN_HTML_PATH = "/login.html";
    public static String LOGIN_PATH = "/login";
}

免登陆的话: http://localhost:1111/index?token=xxxx就可以跳过登录直接访问了.目的是为了在手机端想直接访问监控数据,但是不用登录,在内部直接使用.但是千万不要泄露了.

当然免你还可以更强化一点,将token做个有效期,用个HashSet保存,过期了直接重新换个随机数或者其他的。生成之后通过钉钉或者邮箱直接携带token发送出去。有效期1个小时,每天固定生成24个大小的token。

以上就是登录拦截的简单的实现,主要是为了给有这些需求的人节省时间。

主要是涵盖了登录\登出\免登录这些功能,非常简单,可以基于以上代码进行改造。

有问题直接留言,我看到了会回复的。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值